@jungvonmatt/sb-migrate
Version:
CLI tool for managing Storyblok schema and content migrations
281 lines • 10.3 kB
JavaScript
"use strict";
/**
* @file migration-flow.test.ts
* @description Integration tests for the core migration flow functionality.
*
* This test suite focuses on verifying the end-to-end behavior of migration flows,
* ensuring that the system correctly handles the complete lifecycle of migrations
* from start to finish. It tests the integration between different handlers and
* their interaction with the Storyblok API.
*
* Key aspects tested:
* 1. Complete migration flows (create, update, delete) for various content types
* 2. Error handling and recovery during migration execution
* 3. Dry run functionality
* 4. API interaction patterns
*
* This suite complements migration-handlers.test.ts by focusing on the complete
* flow rather than individual handler behaviors. While migration-handlers.test.ts
* tests the individual components in isolation, this suite verifies their
* integration and interaction.
*
* @see migration-handlers.test.ts for detailed handler-specific tests
*/
Object.defineProperty(exports, "__esModule", { value: true });
const vitest_1 = require("vitest");
const api_1 = require("../../utils/api");
const handlers_1 = require("../../handlers");
const setup_1 = require("../setup");
// Mock the external API calls
vitest_1.vi.mock("../../utils/api", () => {
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 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 datasourceEntries = {
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(),
update: vitest_1.vi.fn(),
};
const componentGroups = {
getAll: vitest_1.vi.fn(),
};
return {
// Export the api object
api: {
components,
componentGroups,
datasources,
datasourceEntries,
stories,
},
datasources,
components,
datasourceEntries,
};
});
// Integration test suite that verifies
// the communication between the actual handlers and the API
(0, vitest_1.describe)("Integration Tests: Migration Flow", () => {
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 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();
(0, setup_1.clearConsoleOutput)();
// Mock API responses with correct structure
api_1.api.components.getAll.mockResolvedValue({
data: { components: [] },
});
api_1.api.components.get.mockResolvedValue({
data: { component: mockComponent },
});
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.datasources.getAll.mockResolvedValue({
data: { datasources: [] },
});
api_1.api.datasources.has.mockResolvedValue(false);
api_1.api.datasources.create.mockResolvedValue({
data: { datasource: mockDatasource },
});
api_1.api.datasources.get.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" },
},
});
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: {},
});
});
(0, vitest_1.afterEach)(() => {
vitest_1.vi.resetAllMocks();
});
(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();
const output = (0, setup_1.getConsoleOutput)();
(0, vitest_1.expect)(output).toContainEqual({
type: "log",
args: [vitest_1.expect.stringContaining("Creating component: test-component")],
});
(0, vitest_1.expect)(output).toContainEqual({
type: "log",
args: [
vitest_1.expect.stringContaining("Updating fields for component: test-component"),
],
});
(0, vitest_1.expect)(output).toContainEqual({
type: "log",
args: [
vitest_1.expect.stringContaining("Component created successfully: test-component"),
],
});
});
(0, vitest_1.it)("should handle component deletion flow", async () => {
api_1.api.components.getAll.mockResolvedValue({
data: {
components: [{ id: 123, name: "delete-component" }],
},
});
await (0, handlers_1.handleDeleteComponent)({ name: "delete-component" }, { isDryrun: false });
(0, vitest_1.expect)(api_1.api.components.delete).toHaveBeenCalled();
});
(0, vitest_1.it)("should handle datasource creation flow without errors", async () => {
const errorSpy = vitest_1.vi.spyOn(console, "error");
vitest_1.vi.clearAllMocks();
api_1.api.datasources.getAll.mockResolvedValue({
data: { datasources: [] },
});
api_1.api.datasources.create.mockResolvedValue({
data: { datasource: mockDatasource },
});
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 transform entries flow without errors", async () => {
const errorSpy = vitest_1.vi.spyOn(console, "error");
vitest_1.vi.clearAllMocks();
api_1.api.stories.getAll.mockResolvedValue({
data: {
stories: [
{
id: 1,
full_slug: "test-story",
content: {
component: "test-component",
title: "Original 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.it)("should handle API errors gracefully", 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)("validates that API mocking works correctly", async () => {
vitest_1.vi.clearAllMocks();
await api_1.api.datasources.create({ name: "test", slug: "test" });
await api_1.api.stories.update({
id: 1,
name: "Test",
slug: "test",
content: { component: "test" },
}, {});
(0, vitest_1.expect)(api_1.api.datasources.create).toHaveBeenCalled();
(0, vitest_1.expect)(api_1.api.stories.update).toHaveBeenCalled();
});
});
//# sourceMappingURL=migration-flow.test.js.map