Steps 1-11, still need to do 12
This commit is contained in:
409
tests/integration/scheduled-execution-workflow.test.js
Normal file
409
tests/integration/scheduled-execution-workflow.test.js
Normal file
@@ -0,0 +1,409 @@
|
||||
/**
|
||||
* Integration Tests for Scheduled Execution Workflow
|
||||
* These tests verify the complete scheduled execution functionality works together
|
||||
* Requirements: 1.2, 2.1, 3.1, 3.2, 5.1, 5.2
|
||||
*/
|
||||
|
||||
const ShopifyPriceUpdater = require("../../src/index");
|
||||
const { getConfig } = require("../../src/config/environment");
|
||||
|
||||
// Mock external dependencies but test internal integration
|
||||
jest.mock("../../src/config/environment");
|
||||
jest.mock("../../src/services/shopify");
|
||||
jest.mock("../../src/services/progress");
|
||||
jest.mock("../../src/utils/logger");
|
||||
|
||||
describe("Scheduled Execution Workflow Integration Tests", () => {
|
||||
let mockConfig;
|
||||
let mockShopifyService;
|
||||
|
||||
beforeEach(() => {
|
||||
// Mock base configuration
|
||||
mockConfig = {
|
||||
shopDomain: "test-shop.myshopify.com",
|
||||
accessToken: "test-token",
|
||||
targetTag: "scheduled-test",
|
||||
priceAdjustmentPercentage: 10,
|
||||
operationMode: "update",
|
||||
scheduledExecutionTime: null,
|
||||
isScheduled: false,
|
||||
};
|
||||
|
||||
// Mock Shopify service responses
|
||||
mockShopifyService = {
|
||||
testConnection: jest.fn().mockResolvedValue(true),
|
||||
executeQuery: jest.fn(),
|
||||
executeMutation: jest.fn(),
|
||||
executeWithRetry: jest.fn(),
|
||||
};
|
||||
|
||||
getConfig.mockReturnValue(mockConfig);
|
||||
|
||||
// Mock ShopifyService constructor
|
||||
const ShopifyService = require("../../src/services/shopify");
|
||||
ShopifyService.mockImplementation(() => mockShopifyService);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe("Backward Compatibility", () => {
|
||||
test("should execute immediately when scheduling is not configured", async () => {
|
||||
// Configure without scheduling
|
||||
mockConfig.scheduledExecutionTime = null;
|
||||
mockConfig.isScheduled = false;
|
||||
getConfig.mockReturnValue(mockConfig);
|
||||
|
||||
// Mock product response
|
||||
const mockProductsResponse = {
|
||||
products: {
|
||||
edges: [
|
||||
{
|
||||
node: {
|
||||
id: "gid://shopify/Product/123",
|
||||
title: "Immediate Test Product",
|
||||
tags: ["scheduled-test"],
|
||||
variants: {
|
||||
edges: [
|
||||
{
|
||||
node: {
|
||||
id: "gid://shopify/ProductVariant/456",
|
||||
price: "50.00",
|
||||
compareAtPrice: null,
|
||||
title: "Test Variant",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
pageInfo: { hasNextPage: false, endCursor: null },
|
||||
},
|
||||
};
|
||||
|
||||
const mockUpdateResponse = {
|
||||
productVariantsBulkUpdate: {
|
||||
productVariants: [
|
||||
{
|
||||
id: "gid://shopify/ProductVariant/456",
|
||||
price: "55.00",
|
||||
compareAtPrice: "50.00",
|
||||
},
|
||||
],
|
||||
userErrors: [],
|
||||
},
|
||||
};
|
||||
|
||||
mockShopifyService.executeWithRetry
|
||||
.mockResolvedValueOnce(mockProductsResponse)
|
||||
.mockResolvedValue(mockUpdateResponse);
|
||||
|
||||
const app = new ShopifyPriceUpdater();
|
||||
const exitCode = await app.run();
|
||||
|
||||
// Verify immediate execution
|
||||
expect(exitCode).toBe(0);
|
||||
|
||||
// Verify normal workflow was executed
|
||||
expect(mockShopifyService.executeWithRetry).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
test("should maintain rollback functionality without scheduling", async () => {
|
||||
// Configure rollback mode without scheduling
|
||||
const rollbackConfig = {
|
||||
...mockConfig,
|
||||
operationMode: "rollback",
|
||||
scheduledExecutionTime: null,
|
||||
isScheduled: false,
|
||||
};
|
||||
getConfig.mockReturnValue(rollbackConfig);
|
||||
|
||||
// Mock rollback product response
|
||||
const mockProductsResponse = {
|
||||
products: {
|
||||
edges: [
|
||||
{
|
||||
node: {
|
||||
id: "gid://shopify/Product/123",
|
||||
title: "Rollback Test Product",
|
||||
tags: ["scheduled-test"],
|
||||
variants: {
|
||||
edges: [
|
||||
{
|
||||
node: {
|
||||
id: "gid://shopify/ProductVariant/456",
|
||||
price: "55.00",
|
||||
compareAtPrice: "50.00",
|
||||
title: "Test Variant",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
pageInfo: { hasNextPage: false, endCursor: null },
|
||||
},
|
||||
};
|
||||
|
||||
const mockRollbackResponse = {
|
||||
productVariantsBulkUpdate: {
|
||||
productVariants: [
|
||||
{
|
||||
id: "gid://shopify/ProductVariant/456",
|
||||
price: "50.00",
|
||||
compareAtPrice: null,
|
||||
},
|
||||
],
|
||||
userErrors: [],
|
||||
},
|
||||
};
|
||||
|
||||
mockShopifyService.executeWithRetry
|
||||
.mockResolvedValueOnce(mockProductsResponse)
|
||||
.mockResolvedValue(mockRollbackResponse);
|
||||
|
||||
const app = new ShopifyPriceUpdater();
|
||||
const exitCode = await app.run();
|
||||
|
||||
// Verify immediate rollback execution
|
||||
expect(exitCode).toBe(0);
|
||||
|
||||
// Verify rollback workflow was executed
|
||||
expect(mockShopifyService.executeWithRetry).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Scheduled Update Workflow", () => {
|
||||
test("should execute complete scheduled update workflow successfully", async () => {
|
||||
// Set up scheduled execution for immediate execution (past time)
|
||||
const scheduledTime = new Date(Date.now() - 1000); // 1 second ago
|
||||
const scheduledConfig = {
|
||||
...mockConfig,
|
||||
scheduledExecutionTime: scheduledTime,
|
||||
isScheduled: true,
|
||||
operationMode: "update",
|
||||
};
|
||||
getConfig.mockReturnValue(scheduledConfig);
|
||||
|
||||
// Mock product fetching response
|
||||
const mockProductsResponse = {
|
||||
products: {
|
||||
edges: [
|
||||
{
|
||||
node: {
|
||||
id: "gid://shopify/Product/123",
|
||||
title: "Scheduled Test Product",
|
||||
tags: ["scheduled-test"],
|
||||
variants: {
|
||||
edges: [
|
||||
{
|
||||
node: {
|
||||
id: "gid://shopify/ProductVariant/456",
|
||||
price: "50.00",
|
||||
compareAtPrice: null,
|
||||
title: "Test Variant",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
hasNextPage: false,
|
||||
endCursor: null,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Mock successful update response
|
||||
const mockUpdateResponse = {
|
||||
productVariantsBulkUpdate: {
|
||||
productVariants: [
|
||||
{
|
||||
id: "gid://shopify/ProductVariant/456",
|
||||
price: "55.00",
|
||||
compareAtPrice: "50.00",
|
||||
},
|
||||
],
|
||||
userErrors: [],
|
||||
},
|
||||
};
|
||||
|
||||
mockShopifyService.executeWithRetry
|
||||
.mockResolvedValueOnce(mockProductsResponse)
|
||||
.mockResolvedValue(mockUpdateResponse);
|
||||
|
||||
// Start the application
|
||||
const app = new ShopifyPriceUpdater();
|
||||
const exitCode = await app.run();
|
||||
|
||||
// Verify successful completion
|
||||
expect(exitCode).toBe(0);
|
||||
|
||||
// Verify Shopify API calls were made
|
||||
expect(mockShopifyService.executeWithRetry).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
test("should execute complete scheduled rollback workflow successfully", async () => {
|
||||
// Set up scheduled execution for rollback mode
|
||||
const scheduledTime = new Date(Date.now() - 1000); // 1 second ago
|
||||
const scheduledConfig = {
|
||||
...mockConfig,
|
||||
scheduledExecutionTime: scheduledTime,
|
||||
isScheduled: true,
|
||||
operationMode: "rollback",
|
||||
};
|
||||
getConfig.mockReturnValue(scheduledConfig);
|
||||
|
||||
// Mock product fetching response for rollback
|
||||
const mockProductsResponse = {
|
||||
products: {
|
||||
edges: [
|
||||
{
|
||||
node: {
|
||||
id: "gid://shopify/Product/123",
|
||||
title: "Rollback Test Product",
|
||||
tags: ["scheduled-test"],
|
||||
variants: {
|
||||
edges: [
|
||||
{
|
||||
node: {
|
||||
id: "gid://shopify/ProductVariant/456",
|
||||
price: "55.00",
|
||||
compareAtPrice: "50.00",
|
||||
title: "Test Variant",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
hasNextPage: false,
|
||||
endCursor: null,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Mock successful rollback response
|
||||
const mockRollbackResponse = {
|
||||
productVariantsBulkUpdate: {
|
||||
productVariants: [
|
||||
{
|
||||
id: "gid://shopify/ProductVariant/456",
|
||||
price: "50.00",
|
||||
compareAtPrice: null,
|
||||
},
|
||||
],
|
||||
userErrors: [],
|
||||
},
|
||||
};
|
||||
|
||||
mockShopifyService.executeWithRetry
|
||||
.mockResolvedValueOnce(mockProductsResponse)
|
||||
.mockResolvedValue(mockRollbackResponse);
|
||||
|
||||
// Start the application
|
||||
const app = new ShopifyPriceUpdater();
|
||||
const exitCode = await app.run();
|
||||
|
||||
// Verify successful completion
|
||||
expect(exitCode).toBe(0);
|
||||
|
||||
// Verify Shopify API calls were made
|
||||
expect(mockShopifyService.executeWithRetry).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Cancellation During Countdown", () => {
|
||||
test("should handle cancellation during countdown period gracefully", async () => {
|
||||
// Set up scheduled execution for future time
|
||||
const scheduledTime = new Date(Date.now() + 5000); // 5 seconds in future
|
||||
const scheduledConfig = {
|
||||
...mockConfig,
|
||||
scheduledExecutionTime: scheduledTime,
|
||||
isScheduled: true,
|
||||
};
|
||||
getConfig.mockReturnValue(scheduledConfig);
|
||||
|
||||
// Start the application
|
||||
const app = new ShopifyPriceUpdater();
|
||||
|
||||
// Set up cancellation state management
|
||||
app.setSchedulingActive = jest.fn();
|
||||
app.setOperationInProgress = jest.fn();
|
||||
|
||||
const runPromise = app.run();
|
||||
|
||||
// Simulate cancellation by calling cleanup on schedule service after a short delay
|
||||
setTimeout(() => {
|
||||
if (app.scheduleService) {
|
||||
app.scheduleService.cleanup();
|
||||
}
|
||||
}, 50);
|
||||
|
||||
const exitCode = await runPromise;
|
||||
|
||||
// Verify cancellation was handled (should return 0 for clean cancellation)
|
||||
expect(exitCode).toBe(0);
|
||||
|
||||
// Verify no product operations were executed
|
||||
expect(mockShopifyService.executeWithRetry).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Error Handling in Scheduled Operations", () => {
|
||||
test("should handle API connection failures during scheduled execution", async () => {
|
||||
// Set up scheduled execution
|
||||
const scheduledTime = new Date(Date.now() - 1000); // 1 second ago
|
||||
const scheduledConfig = {
|
||||
...mockConfig,
|
||||
scheduledExecutionTime: scheduledTime,
|
||||
isScheduled: true,
|
||||
};
|
||||
getConfig.mockReturnValue(scheduledConfig);
|
||||
|
||||
// Mock connection failure
|
||||
mockShopifyService.testConnection.mockResolvedValue(false);
|
||||
|
||||
const app = new ShopifyPriceUpdater();
|
||||
const exitCode = await app.run();
|
||||
|
||||
// Verify failure handling
|
||||
expect(exitCode).toBe(1);
|
||||
|
||||
// Verify connection was tested
|
||||
expect(mockShopifyService.testConnection).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("should handle product fetching failures during scheduled execution", async () => {
|
||||
// Set up scheduled execution
|
||||
const scheduledTime = new Date(Date.now() - 1000); // 1 second ago
|
||||
const scheduledConfig = {
|
||||
...mockConfig,
|
||||
scheduledExecutionTime: scheduledTime,
|
||||
isScheduled: true,
|
||||
};
|
||||
getConfig.mockReturnValue(scheduledConfig);
|
||||
|
||||
// Mock product fetching failure
|
||||
mockShopifyService.executeWithRetry.mockRejectedValue(
|
||||
new Error("GraphQL API error during scheduled execution")
|
||||
);
|
||||
|
||||
const app = new ShopifyPriceUpdater();
|
||||
const exitCode = await app.run();
|
||||
|
||||
// Verify failure handling
|
||||
expect(exitCode).toBe(1);
|
||||
|
||||
// Verify product fetching was attempted
|
||||
expect(mockShopifyService.executeWithRetry).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user