Just a whole lot of crap
This commit is contained in:
290
tests/tui/integration/cliTuiCompatibility.test.js
Normal file
290
tests/tui/integration/cliTuiCompatibility.test.js
Normal file
@@ -0,0 +1,290 @@
|
||||
const fs = require("fs").promises;
|
||||
const path = require("path");
|
||||
|
||||
// Mock the services to avoid actual API calls during testing
|
||||
jest.mock("../../../src/services/shopify");
|
||||
jest.mock("../../../src/services/product");
|
||||
jest.mock("../../../src/services/progress");
|
||||
|
||||
describe("CLI/TUI Compatibility", () => {
|
||||
const originalEnv = process.env;
|
||||
|
||||
beforeEach(() => {
|
||||
// Reset environment
|
||||
jest.resetModules();
|
||||
process.env = { ...originalEnv };
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Restore original environment
|
||||
process.env = originalEnv;
|
||||
});
|
||||
|
||||
describe("Configuration Compatibility", () => {
|
||||
test("should use same configuration system for both CLI and TUI", () => {
|
||||
// Set environment variables that both CLI and TUI should use
|
||||
process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com";
|
||||
process.env.SHOPIFY_ACCESS_TOKEN = "test-token";
|
||||
process.env.TARGET_TAG = "test-tag";
|
||||
process.env.PRICE_ADJUSTMENT_PERCENTAGE = "10";
|
||||
process.env.OPERATION_MODE = "update";
|
||||
|
||||
// Both CLI and TUI use the same configuration module
|
||||
const { getConfig } = require("../../../src/config/environment");
|
||||
const config = getConfig();
|
||||
|
||||
// Verify configuration is loaded correctly
|
||||
expect(config.shopDomain).toBe("test-shop.myshopify.com");
|
||||
expect(config.accessToken).toBe("test-token");
|
||||
expect(config.targetTag).toBe("test-tag");
|
||||
expect(config.priceAdjustmentPercentage).toBe(10);
|
||||
expect(config.operationMode).toBe("update");
|
||||
});
|
||||
|
||||
test("should handle update mode configuration", () => {
|
||||
process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com";
|
||||
process.env.SHOPIFY_ACCESS_TOKEN = "test-token";
|
||||
process.env.TARGET_TAG = "update-tag";
|
||||
process.env.OPERATION_MODE = "update";
|
||||
process.env.PRICE_ADJUSTMENT_PERCENTAGE = "15";
|
||||
|
||||
const { getConfig } = require("../../../src/config/environment");
|
||||
const config = getConfig();
|
||||
|
||||
expect(config.operationMode).toBe("update");
|
||||
expect(config.targetTag).toBe("update-tag");
|
||||
expect(config.priceAdjustmentPercentage).toBe(15);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Service Integration Compatibility", () => {
|
||||
test("should use same service classes for both CLI and TUI", () => {
|
||||
const ShopifyService = require("../../../src/services/shopify");
|
||||
const ProductService = require("../../../src/services/product");
|
||||
const ProgressService = require("../../../src/services/progress");
|
||||
|
||||
// Both CLI and TUI should be able to create the same service instances
|
||||
const shopifyService = new ShopifyService();
|
||||
const productService = new ProductService();
|
||||
const progressService = new ProgressService();
|
||||
|
||||
expect(shopifyService).toBeDefined();
|
||||
expect(productService).toBeDefined();
|
||||
expect(progressService).toBeDefined();
|
||||
|
||||
// Verify services have the same API
|
||||
expect(typeof shopifyService.testConnection).toBe("function");
|
||||
expect(typeof shopifyService.executeQuery).toBe("function");
|
||||
expect(typeof shopifyService.executeMutation).toBe("function");
|
||||
|
||||
expect(typeof productService.fetchProductsByTag).toBe("function");
|
||||
expect(typeof productService.updateProductPrices).toBe("function");
|
||||
expect(typeof productService.rollbackProductPrices).toBe("function");
|
||||
|
||||
expect(typeof progressService.logOperationStart).toBe("function");
|
||||
expect(typeof progressService.logProductUpdate).toBe("function");
|
||||
expect(typeof progressService.logCompletionSummary).toBe("function");
|
||||
});
|
||||
});
|
||||
|
||||
describe("File System Compatibility", () => {
|
||||
test("should use same progress file system for both CLI and TUI", () => {
|
||||
// Since ProgressService is mocked, we'll test the concept rather than implementation
|
||||
const ProgressService = require("../../../src/services/progress");
|
||||
|
||||
// Both CLI and TUI should be able to create ProgressService instances
|
||||
const progressService1 = new ProgressService();
|
||||
const progressService2 = new ProgressService();
|
||||
|
||||
// Both should have the same API
|
||||
expect(progressService1).toBeDefined();
|
||||
expect(progressService2).toBeDefined();
|
||||
expect(typeof progressService1.logOperationStart).toBe("function");
|
||||
expect(typeof progressService2.logOperationStart).toBe("function");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Entry Point Compatibility", () => {
|
||||
test("should have separate entry points that don't conflict", () => {
|
||||
// CLI entry point should be importable
|
||||
expect(() => {
|
||||
const cliModule = require("../../../src/index.js");
|
||||
expect(cliModule).toBeDefined();
|
||||
}).not.toThrow();
|
||||
|
||||
// TUI entry point should be importable (but we'll skip the actual import due to JSX issues in tests)
|
||||
// Instead, verify the file exists and has the expected structure
|
||||
const tuiEntryPath = path.join(__dirname, "../../../src/tui-entry.js");
|
||||
expect(() => {
|
||||
const fs = require("fs");
|
||||
const content = fs.readFileSync(tuiEntryPath, "utf8");
|
||||
expect(content).toContain("TuiApplication");
|
||||
expect(content).toContain("render");
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Package.json Script Compatibility", () => {
|
||||
test("should have separate scripts for CLI and TUI", () => {
|
||||
const packageJson = require("../../../package.json");
|
||||
|
||||
// CLI scripts
|
||||
expect(packageJson.scripts.start).toBe("node src/index.js");
|
||||
expect(packageJson.scripts.update).toContain("node src/index.js");
|
||||
expect(packageJson.scripts.rollback).toContain("node src/index.js");
|
||||
|
||||
// TUI script
|
||||
expect(packageJson.scripts.tui).toContain("src/tui-entry.js");
|
||||
|
||||
// Both should be able to coexist
|
||||
expect(packageJson.scripts.start).not.toBe(packageJson.scripts.tui);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Operational Compatibility", () => {
|
||||
test("should support same operation modes in both interfaces", () => {
|
||||
const validModes = ["update", "rollback"];
|
||||
|
||||
validModes.forEach((mode) => {
|
||||
// Reset modules to get fresh config
|
||||
jest.resetModules();
|
||||
|
||||
process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com";
|
||||
process.env.SHOPIFY_ACCESS_TOKEN = "test-token";
|
||||
process.env.TARGET_TAG = "test-tag";
|
||||
process.env.PRICE_ADJUSTMENT_PERCENTAGE = "10";
|
||||
process.env.OPERATION_MODE = mode;
|
||||
|
||||
const { getConfig } = require("../../../src/config/environment");
|
||||
const config = getConfig();
|
||||
expect(config.operationMode).toBe(mode);
|
||||
});
|
||||
});
|
||||
|
||||
test("should handle configuration validation consistently", () => {
|
||||
// Test that both CLI and TUI would handle missing configuration the same way
|
||||
process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com";
|
||||
process.env.SHOPIFY_ACCESS_TOKEN = "test-token";
|
||||
process.env.TARGET_TAG = "test-tag";
|
||||
process.env.PRICE_ADJUSTMENT_PERCENTAGE = "10";
|
||||
process.env.OPERATION_MODE = "update";
|
||||
|
||||
const { getConfig } = require("../../../src/config/environment");
|
||||
|
||||
// Valid configuration should work
|
||||
expect(() => getConfig()).not.toThrow();
|
||||
|
||||
// Both CLI and TUI use the same validation logic
|
||||
const config = getConfig();
|
||||
expect(config).toBeDefined();
|
||||
expect(config.shopDomain).toBeDefined();
|
||||
expect(config.accessToken).toBeDefined();
|
||||
expect(config.targetTag).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("State Management Compatibility", () => {
|
||||
test("should not share state between CLI and TUI instances", () => {
|
||||
// CLI and TUI should be independent - no shared global state
|
||||
const ShopifyService = require("../../../src/services/shopify");
|
||||
|
||||
// Create separate instances (as CLI and TUI would)
|
||||
const cliService = new ShopifyService();
|
||||
const tuiService = new ShopifyService();
|
||||
|
||||
// They should be separate instances
|
||||
expect(cliService).not.toBe(tuiService);
|
||||
|
||||
// They should be different instances but have same structure
|
||||
expect(cliService === tuiService).toBe(false);
|
||||
expect(typeof cliService.testConnection).toBe(
|
||||
typeof tuiService.testConnection
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Dependency Compatibility", () => {
|
||||
test("should use compatible dependencies for both interfaces", () => {
|
||||
const packageJson = require("../../../package.json");
|
||||
|
||||
// Core dependencies that both CLI and TUI use
|
||||
const sharedDependencies = [
|
||||
"@shopify/shopify-api",
|
||||
"dotenv",
|
||||
"node-fetch",
|
||||
];
|
||||
|
||||
sharedDependencies.forEach((dep) => {
|
||||
expect(packageJson.dependencies[dep]).toBeDefined();
|
||||
});
|
||||
|
||||
// TUI-specific dependencies
|
||||
const tuiDependencies = [
|
||||
"ink",
|
||||
"react",
|
||||
"ink-text-input",
|
||||
"ink-select-input",
|
||||
"ink-spinner",
|
||||
];
|
||||
|
||||
tuiDependencies.forEach((dep) => {
|
||||
expect(packageJson.dependencies[dep]).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Service API Compatibility", () => {
|
||||
test("should maintain consistent service APIs for both CLI and TUI", () => {
|
||||
// Test that services maintain their expected API structure
|
||||
const ShopifyService = require("../../../src/services/shopify");
|
||||
const ProductService = require("../../../src/services/product");
|
||||
const ProgressService = require("../../../src/services/progress");
|
||||
|
||||
const shopifyService = new ShopifyService();
|
||||
const productService = new ProductService();
|
||||
const progressService = new ProgressService();
|
||||
|
||||
// ShopifyService API
|
||||
const shopifyMethods = [
|
||||
"testConnection",
|
||||
"executeQuery",
|
||||
"executeMutation",
|
||||
"executeWithRetry",
|
||||
"getApiCallLimit",
|
||||
];
|
||||
|
||||
shopifyMethods.forEach((method) => {
|
||||
expect(typeof shopifyService[method]).toBe("function");
|
||||
});
|
||||
|
||||
// ProductService API
|
||||
const productMethods = [
|
||||
"fetchProductsByTag",
|
||||
"updateProductPrices",
|
||||
"rollbackProductPrices",
|
||||
"validateProducts",
|
||||
"validateProductsForRollback",
|
||||
"getProductSummary",
|
||||
];
|
||||
|
||||
productMethods.forEach((method) => {
|
||||
expect(typeof productService[method]).toBe("function");
|
||||
});
|
||||
|
||||
// ProgressService API
|
||||
const progressMethods = [
|
||||
"logOperationStart",
|
||||
"logRollbackStart",
|
||||
"logProductUpdate",
|
||||
"logRollbackUpdate",
|
||||
"logError",
|
||||
"logCompletionSummary",
|
||||
"logRollbackSummary",
|
||||
];
|
||||
|
||||
progressMethods.forEach((method) => {
|
||||
expect(typeof progressService[method]).toBe("function");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
436
tests/tui/integration/productProgressService.test.js
Normal file
436
tests/tui/integration/productProgressService.test.js
Normal file
@@ -0,0 +1,436 @@
|
||||
const ShopifyService = require("../../../src/services/shopify");
|
||||
const ProductService = require("../../../src/services/product");
|
||||
const ProgressService = require("../../../src/services/progress");
|
||||
|
||||
// Mock the services to avoid actual API calls during testing
|
||||
jest.mock("../../../src/services/shopify");
|
||||
jest.mock("../../../src/services/product");
|
||||
jest.mock("../../../src/services/progress");
|
||||
|
||||
describe("TUI ProductService and ProgressService Integration", () => {
|
||||
let mockShopifyService;
|
||||
let mockProductService;
|
||||
let mockProgressService;
|
||||
|
||||
beforeEach(() => {
|
||||
// Reset all mocks
|
||||
jest.clearAllMocks();
|
||||
|
||||
// Create mock ShopifyService instance
|
||||
mockShopifyService = {
|
||||
testConnection: jest.fn(),
|
||||
executeQuery: jest.fn(),
|
||||
executeMutation: jest.fn(),
|
||||
executeWithRetry: jest.fn(),
|
||||
};
|
||||
|
||||
// Create mock ProductService instance
|
||||
mockProductService = {
|
||||
fetchProductsByTag: jest.fn(),
|
||||
updateProductPrices: jest.fn(),
|
||||
rollbackProductPrices: jest.fn(),
|
||||
validateProducts: jest.fn(),
|
||||
validateProductsForRollback: jest.fn(),
|
||||
getProductSummary: jest.fn(),
|
||||
};
|
||||
|
||||
// Create mock ProgressService instance
|
||||
mockProgressService = {
|
||||
logOperationStart: jest.fn(),
|
||||
logRollbackStart: jest.fn(),
|
||||
logProductUpdate: jest.fn(),
|
||||
logRollbackUpdate: jest.fn(),
|
||||
logError: jest.fn(),
|
||||
logCompletionSummary: jest.fn(),
|
||||
logRollbackSummary: jest.fn(),
|
||||
};
|
||||
|
||||
// Mock the service constructors
|
||||
ShopifyService.mockImplementation(() => mockShopifyService);
|
||||
ProductService.mockImplementation(() => mockProductService);
|
||||
ProgressService.mockImplementation(() => mockProgressService);
|
||||
});
|
||||
|
||||
describe("ProductService Integration", () => {
|
||||
test("should fetch products by tag", async () => {
|
||||
const mockProducts = [
|
||||
{
|
||||
id: "product1",
|
||||
title: "Test Product 1",
|
||||
variants: [{ id: "variant1", price: 10.0 }],
|
||||
},
|
||||
];
|
||||
mockProductService.fetchProductsByTag.mockResolvedValue(mockProducts);
|
||||
|
||||
const service = new ProductService();
|
||||
const products = await service.fetchProductsByTag("test-tag");
|
||||
|
||||
expect(mockProductService.fetchProductsByTag).toHaveBeenCalledWith(
|
||||
"test-tag"
|
||||
);
|
||||
expect(products).toEqual(mockProducts);
|
||||
});
|
||||
|
||||
test("should update product prices", async () => {
|
||||
const mockProducts = [
|
||||
{
|
||||
id: "product1",
|
||||
title: "Test Product 1",
|
||||
variants: [{ id: "variant1", price: 10.0 }],
|
||||
},
|
||||
];
|
||||
const mockResults = {
|
||||
totalProducts: 1,
|
||||
totalVariants: 1,
|
||||
successfulUpdates: 1,
|
||||
failedUpdates: 0,
|
||||
errors: [],
|
||||
};
|
||||
mockProductService.updateProductPrices.mockResolvedValue(mockResults);
|
||||
|
||||
const service = new ProductService();
|
||||
const results = await service.updateProductPrices(mockProducts, 10);
|
||||
|
||||
expect(mockProductService.updateProductPrices).toHaveBeenCalledWith(
|
||||
mockProducts,
|
||||
10
|
||||
);
|
||||
expect(results).toEqual(mockResults);
|
||||
});
|
||||
|
||||
test("should rollback product prices", async () => {
|
||||
const mockProducts = [
|
||||
{
|
||||
id: "product1",
|
||||
title: "Test Product 1",
|
||||
variants: [{ id: "variant1", price: 11.0, compareAtPrice: 10.0 }],
|
||||
},
|
||||
];
|
||||
const mockResults = {
|
||||
totalProducts: 1,
|
||||
totalVariants: 1,
|
||||
successfulRollbacks: 1,
|
||||
failedRollbacks: 0,
|
||||
skippedVariants: 0,
|
||||
errors: [],
|
||||
};
|
||||
mockProductService.rollbackProductPrices.mockResolvedValue(mockResults);
|
||||
|
||||
const service = new ProductService();
|
||||
const results = await service.rollbackProductPrices(mockProducts);
|
||||
|
||||
expect(mockProductService.rollbackProductPrices).toHaveBeenCalledWith(
|
||||
mockProducts
|
||||
);
|
||||
expect(results).toEqual(mockResults);
|
||||
});
|
||||
|
||||
test("should validate products", async () => {
|
||||
const mockProducts = [
|
||||
{
|
||||
id: "product1",
|
||||
title: "Test Product 1",
|
||||
variants: [{ id: "variant1", price: 10.0 }],
|
||||
},
|
||||
];
|
||||
mockProductService.validateProducts.mockResolvedValue(mockProducts);
|
||||
|
||||
const service = new ProductService();
|
||||
const validProducts = await service.validateProducts(mockProducts);
|
||||
|
||||
expect(mockProductService.validateProducts).toHaveBeenCalledWith(
|
||||
mockProducts
|
||||
);
|
||||
expect(validProducts).toEqual(mockProducts);
|
||||
});
|
||||
|
||||
test("should validate products for rollback", async () => {
|
||||
const mockProducts = [
|
||||
{
|
||||
id: "product1",
|
||||
title: "Test Product 1",
|
||||
variants: [{ id: "variant1", price: 11.0, compareAtPrice: 10.0 }],
|
||||
},
|
||||
];
|
||||
mockProductService.validateProductsForRollback.mockResolvedValue(
|
||||
mockProducts
|
||||
);
|
||||
|
||||
const service = new ProductService();
|
||||
const validProducts = await service.validateProductsForRollback(
|
||||
mockProducts
|
||||
);
|
||||
|
||||
expect(
|
||||
mockProductService.validateProductsForRollback
|
||||
).toHaveBeenCalledWith(mockProducts);
|
||||
expect(validProducts).toEqual(mockProducts);
|
||||
});
|
||||
|
||||
test("should get product summary", () => {
|
||||
const mockProducts = [
|
||||
{
|
||||
id: "product1",
|
||||
title: "Test Product 1",
|
||||
variants: [{ id: "variant1", price: 10.0 }],
|
||||
},
|
||||
];
|
||||
const mockSummary = {
|
||||
totalProducts: 1,
|
||||
totalVariants: 1,
|
||||
priceRange: { min: 10.0, max: 10.0 },
|
||||
};
|
||||
mockProductService.getProductSummary.mockReturnValue(mockSummary);
|
||||
|
||||
const service = new ProductService();
|
||||
const summary = service.getProductSummary(mockProducts);
|
||||
|
||||
expect(mockProductService.getProductSummary).toHaveBeenCalledWith(
|
||||
mockProducts
|
||||
);
|
||||
expect(summary).toEqual(mockSummary);
|
||||
});
|
||||
});
|
||||
|
||||
describe("ProgressService Integration", () => {
|
||||
test("should log operation start", async () => {
|
||||
const mockConfig = {
|
||||
targetTag: "test-tag",
|
||||
priceAdjustmentPercentage: 10,
|
||||
};
|
||||
mockProgressService.logOperationStart.mockResolvedValue();
|
||||
|
||||
const service = new ProgressService();
|
||||
await service.logOperationStart(mockConfig);
|
||||
|
||||
expect(mockProgressService.logOperationStart).toHaveBeenCalledWith(
|
||||
mockConfig
|
||||
);
|
||||
});
|
||||
|
||||
test("should log rollback start", async () => {
|
||||
const mockConfig = { targetTag: "test-tag" };
|
||||
mockProgressService.logRollbackStart.mockResolvedValue();
|
||||
|
||||
const service = new ProgressService();
|
||||
await service.logRollbackStart(mockConfig);
|
||||
|
||||
expect(mockProgressService.logRollbackStart).toHaveBeenCalledWith(
|
||||
mockConfig
|
||||
);
|
||||
});
|
||||
|
||||
test("should log product update", async () => {
|
||||
const mockEntry = {
|
||||
productId: "product1",
|
||||
productTitle: "Test Product",
|
||||
variantId: "variant1",
|
||||
oldPrice: 10.0,
|
||||
newPrice: 11.0,
|
||||
compareAtPrice: 10.0,
|
||||
};
|
||||
mockProgressService.logProductUpdate.mockResolvedValue();
|
||||
|
||||
const service = new ProgressService();
|
||||
await service.logProductUpdate(mockEntry);
|
||||
|
||||
expect(mockProgressService.logProductUpdate).toHaveBeenCalledWith(
|
||||
mockEntry
|
||||
);
|
||||
});
|
||||
|
||||
test("should log rollback update", async () => {
|
||||
const mockEntry = {
|
||||
productId: "product1",
|
||||
productTitle: "Test Product",
|
||||
variantId: "variant1",
|
||||
oldPrice: 11.0,
|
||||
newPrice: 10.0,
|
||||
compareAtPrice: 10.0,
|
||||
};
|
||||
mockProgressService.logRollbackUpdate.mockResolvedValue();
|
||||
|
||||
const service = new ProgressService();
|
||||
await service.logRollbackUpdate(mockEntry);
|
||||
|
||||
expect(mockProgressService.logRollbackUpdate).toHaveBeenCalledWith(
|
||||
mockEntry
|
||||
);
|
||||
});
|
||||
|
||||
test("should log error", async () => {
|
||||
const mockEntry = {
|
||||
productId: "product1",
|
||||
productTitle: "Test Product",
|
||||
variantId: "variant1",
|
||||
errorMessage: "Test error",
|
||||
};
|
||||
mockProgressService.logError.mockResolvedValue();
|
||||
|
||||
const service = new ProgressService();
|
||||
await service.logError(mockEntry);
|
||||
|
||||
expect(mockProgressService.logError).toHaveBeenCalledWith(mockEntry);
|
||||
});
|
||||
|
||||
test("should log completion summary", async () => {
|
||||
const mockSummary = {
|
||||
totalProducts: 1,
|
||||
successfulUpdates: 1,
|
||||
failedUpdates: 0,
|
||||
startTime: new Date(),
|
||||
};
|
||||
mockProgressService.logCompletionSummary.mockResolvedValue();
|
||||
|
||||
const service = new ProgressService();
|
||||
await service.logCompletionSummary(mockSummary);
|
||||
|
||||
expect(mockProgressService.logCompletionSummary).toHaveBeenCalledWith(
|
||||
mockSummary
|
||||
);
|
||||
});
|
||||
|
||||
test("should log rollback summary", async () => {
|
||||
const mockSummary = {
|
||||
totalProducts: 1,
|
||||
totalVariants: 1,
|
||||
successfulRollbacks: 1,
|
||||
failedRollbacks: 0,
|
||||
skippedVariants: 0,
|
||||
startTime: new Date(),
|
||||
};
|
||||
mockProgressService.logRollbackSummary.mockResolvedValue();
|
||||
|
||||
const service = new ProgressService();
|
||||
await service.logRollbackSummary(mockSummary);
|
||||
|
||||
expect(mockProgressService.logRollbackSummary).toHaveBeenCalledWith(
|
||||
mockSummary
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Service Integration Workflow", () => {
|
||||
test("should support complete update workflow", async () => {
|
||||
// Mock the complete workflow
|
||||
const mockProducts = [
|
||||
{
|
||||
id: "product1",
|
||||
title: "Test Product 1",
|
||||
variants: [{ id: "variant1", price: 10.0 }],
|
||||
},
|
||||
];
|
||||
const mockConfig = {
|
||||
targetTag: "test-tag",
|
||||
priceAdjustmentPercentage: 10,
|
||||
};
|
||||
const mockResults = {
|
||||
totalProducts: 1,
|
||||
totalVariants: 1,
|
||||
successfulUpdates: 1,
|
||||
failedUpdates: 0,
|
||||
errors: [],
|
||||
};
|
||||
|
||||
mockProductService.fetchProductsByTag.mockResolvedValue(mockProducts);
|
||||
mockProductService.validateProducts.mockResolvedValue(mockProducts);
|
||||
mockProductService.updateProductPrices.mockResolvedValue(mockResults);
|
||||
mockProgressService.logOperationStart.mockResolvedValue();
|
||||
mockProgressService.logCompletionSummary.mockResolvedValue();
|
||||
|
||||
const productService = new ProductService();
|
||||
const progressService = new ProgressService();
|
||||
|
||||
// Execute workflow
|
||||
await progressService.logOperationStart(mockConfig);
|
||||
const fetchedProducts = await productService.fetchProductsByTag(
|
||||
mockConfig.targetTag
|
||||
);
|
||||
const validProducts = await productService.validateProducts(
|
||||
fetchedProducts
|
||||
);
|
||||
const results = await productService.updateProductPrices(
|
||||
validProducts,
|
||||
mockConfig.priceAdjustmentPercentage
|
||||
);
|
||||
await progressService.logCompletionSummary(results);
|
||||
|
||||
// Verify workflow execution
|
||||
expect(mockProgressService.logOperationStart).toHaveBeenCalledWith(
|
||||
mockConfig
|
||||
);
|
||||
expect(mockProductService.fetchProductsByTag).toHaveBeenCalledWith(
|
||||
mockConfig.targetTag
|
||||
);
|
||||
expect(mockProductService.validateProducts).toHaveBeenCalledWith(
|
||||
mockProducts
|
||||
);
|
||||
expect(mockProductService.updateProductPrices).toHaveBeenCalledWith(
|
||||
mockProducts,
|
||||
mockConfig.priceAdjustmentPercentage
|
||||
);
|
||||
expect(mockProgressService.logCompletionSummary).toHaveBeenCalledWith(
|
||||
mockResults
|
||||
);
|
||||
});
|
||||
|
||||
test("should support complete rollback workflow", async () => {
|
||||
// Mock the complete rollback workflow
|
||||
const mockProducts = [
|
||||
{
|
||||
id: "product1",
|
||||
title: "Test Product 1",
|
||||
variants: [{ id: "variant1", price: 11.0, compareAtPrice: 10.0 }],
|
||||
},
|
||||
];
|
||||
const mockConfig = { targetTag: "test-tag" };
|
||||
const mockResults = {
|
||||
totalProducts: 1,
|
||||
totalVariants: 1,
|
||||
successfulRollbacks: 1,
|
||||
failedRollbacks: 0,
|
||||
skippedVariants: 0,
|
||||
errors: [],
|
||||
};
|
||||
|
||||
mockProductService.fetchProductsByTag.mockResolvedValue(mockProducts);
|
||||
mockProductService.validateProductsForRollback.mockResolvedValue(
|
||||
mockProducts
|
||||
);
|
||||
mockProductService.rollbackProductPrices.mockResolvedValue(mockResults);
|
||||
mockProgressService.logRollbackStart.mockResolvedValue();
|
||||
mockProgressService.logRollbackSummary.mockResolvedValue();
|
||||
|
||||
const productService = new ProductService();
|
||||
const progressService = new ProgressService();
|
||||
|
||||
// Execute rollback workflow
|
||||
await progressService.logRollbackStart(mockConfig);
|
||||
const fetchedProducts = await productService.fetchProductsByTag(
|
||||
mockConfig.targetTag
|
||||
);
|
||||
const validProducts = await productService.validateProductsForRollback(
|
||||
fetchedProducts
|
||||
);
|
||||
const results = await productService.rollbackProductPrices(validProducts);
|
||||
await progressService.logRollbackSummary(results);
|
||||
|
||||
// Verify rollback workflow execution
|
||||
expect(mockProgressService.logRollbackStart).toHaveBeenCalledWith(
|
||||
mockConfig
|
||||
);
|
||||
expect(mockProductService.fetchProductsByTag).toHaveBeenCalledWith(
|
||||
mockConfig.targetTag
|
||||
);
|
||||
expect(
|
||||
mockProductService.validateProductsForRollback
|
||||
).toHaveBeenCalledWith(mockProducts);
|
||||
expect(mockProductService.rollbackProductPrices).toHaveBeenCalledWith(
|
||||
mockProducts
|
||||
);
|
||||
expect(mockProgressService.logRollbackSummary).toHaveBeenCalledWith(
|
||||
mockResults
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
302
tests/tui/integration/responsiveLayout.test.js
Normal file
302
tests/tui/integration/responsiveLayout.test.js
Normal file
@@ -0,0 +1,302 @@
|
||||
/**
|
||||
* Integration tests for responsive layout functionality
|
||||
* Tests different screen size scenarios and component behavior
|
||||
* Requirements: 10.2, 10.3, 10.4
|
||||
*/
|
||||
|
||||
const {
|
||||
getResponsiveDimensions,
|
||||
getColumnLayout,
|
||||
getScrollableDimensions,
|
||||
getTextTruncationLength,
|
||||
getResponsiveSpacing,
|
||||
shouldHideOnSmallScreen,
|
||||
getAdaptiveFontStyle,
|
||||
} = require("../../../src/tui/utils/responsiveLayout.js");
|
||||
|
||||
describe("Responsive Layout Integration", () => {
|
||||
// Test scenarios for different screen sizes
|
||||
const screenSizes = {
|
||||
small: {
|
||||
width: 80,
|
||||
height: 20,
|
||||
layoutConfig: {
|
||||
isSmall: true,
|
||||
isMedium: false,
|
||||
isLarge: false,
|
||||
maxContentWidth: 76,
|
||||
maxContentHeight: 16,
|
||||
columnsCount: 1,
|
||||
showSidebar: false,
|
||||
},
|
||||
},
|
||||
medium: {
|
||||
width: 120,
|
||||
height: 30,
|
||||
layoutConfig: {
|
||||
isSmall: false,
|
||||
isMedium: true,
|
||||
isLarge: false,
|
||||
maxContentWidth: 116,
|
||||
maxContentHeight: 26,
|
||||
columnsCount: 2,
|
||||
showSidebar: true,
|
||||
},
|
||||
},
|
||||
large: {
|
||||
width: 160,
|
||||
height: 40,
|
||||
layoutConfig: {
|
||||
isSmall: false,
|
||||
isMedium: false,
|
||||
isLarge: true,
|
||||
maxContentWidth: 120, // Limited to max 120
|
||||
maxContentHeight: 36,
|
||||
columnsCount: 3,
|
||||
showSidebar: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
describe("Small Screen Behavior", () => {
|
||||
const { layoutConfig } = screenSizes.small;
|
||||
|
||||
test("should provide appropriate dimensions for small screens", () => {
|
||||
const menuDimensions = getResponsiveDimensions(layoutConfig, "menu");
|
||||
const formDimensions = getResponsiveDimensions(layoutConfig, "form");
|
||||
|
||||
expect(menuDimensions.width).toBe(76);
|
||||
expect(menuDimensions.height).toBe(12); // 16 * 0.8 = 12.8, floored to 12
|
||||
expect(formDimensions.width).toBe(76);
|
||||
});
|
||||
|
||||
test("should use single column layout", () => {
|
||||
const columnLayout = getColumnLayout(layoutConfig, 10);
|
||||
|
||||
expect(columnLayout.columns).toBe(1);
|
||||
expect(columnLayout.rows).toBe(10);
|
||||
});
|
||||
|
||||
test("should hide secondary components", () => {
|
||||
expect(shouldHideOnSmallScreen(layoutConfig, "sidebar")).toBe(true);
|
||||
expect(shouldHideOnSmallScreen(layoutConfig, "secondary-info")).toBe(
|
||||
true
|
||||
);
|
||||
expect(shouldHideOnSmallScreen(layoutConfig, "main-content")).toBe(false);
|
||||
});
|
||||
|
||||
test("should use compact spacing", () => {
|
||||
const spacing = getResponsiveSpacing(layoutConfig);
|
||||
|
||||
expect(spacing.padding).toBe(1);
|
||||
expect(spacing.margin).toBe(0);
|
||||
expect(spacing.gap).toBe(0);
|
||||
});
|
||||
|
||||
test("should truncate text appropriately", () => {
|
||||
const truncationLength = getTextTruncationLength(layoutConfig, 50);
|
||||
|
||||
expect(truncationLength).toBe(40); // Math.max(20, 50 - 10)
|
||||
});
|
||||
|
||||
test("should use adaptive font styles", () => {
|
||||
const titleStyle = getAdaptiveFontStyle(layoutConfig, "title");
|
||||
const subtitleStyle = getAdaptiveFontStyle(layoutConfig, "subtitle");
|
||||
|
||||
expect(titleStyle.color).toBe("white"); // Different from large screens
|
||||
expect(subtitleStyle.bold).toBe(false); // Different from large screens
|
||||
});
|
||||
});
|
||||
|
||||
describe("Medium Screen Behavior", () => {
|
||||
const { layoutConfig } = screenSizes.medium;
|
||||
|
||||
test("should provide appropriate dimensions for medium screens", () => {
|
||||
const menuDimensions = getResponsiveDimensions(layoutConfig, "menu");
|
||||
|
||||
expect(menuDimensions.width).toBe(81); // Math.floor(116 * 0.7)
|
||||
expect(menuDimensions.height).toBe(24); // 26 - 2
|
||||
});
|
||||
|
||||
test("should use two column layout", () => {
|
||||
const columnLayout = getColumnLayout(layoutConfig, 10);
|
||||
|
||||
expect(columnLayout.columns).toBe(2);
|
||||
expect(columnLayout.rows).toBe(5); // Math.ceil(10 / 2)
|
||||
});
|
||||
|
||||
test("should show sidebar components", () => {
|
||||
expect(shouldHideOnSmallScreen(layoutConfig, "sidebar")).toBe(false);
|
||||
expect(shouldHideOnSmallScreen(layoutConfig, "secondary-info")).toBe(
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
test("should use normal spacing", () => {
|
||||
const spacing = getResponsiveSpacing(layoutConfig);
|
||||
|
||||
expect(spacing.padding).toBe(2);
|
||||
expect(spacing.margin).toBe(1);
|
||||
expect(spacing.gap).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Large Screen Behavior", () => {
|
||||
const { layoutConfig } = screenSizes.large;
|
||||
|
||||
test("should provide appropriate dimensions for large screens", () => {
|
||||
const menuDimensions = getResponsiveDimensions(layoutConfig, "menu");
|
||||
|
||||
expect(menuDimensions.width).toBe(72); // Math.floor(120 * 0.6)
|
||||
expect(menuDimensions.height).toBe(34); // 36 - 2
|
||||
});
|
||||
|
||||
test("should use three column layout", () => {
|
||||
const columnLayout = getColumnLayout(layoutConfig, 10);
|
||||
|
||||
expect(columnLayout.columns).toBe(3);
|
||||
expect(columnLayout.rows).toBe(4); // Math.ceil(10 / 3)
|
||||
});
|
||||
|
||||
test("should show all components", () => {
|
||||
expect(shouldHideOnSmallScreen(layoutConfig, "sidebar")).toBe(false);
|
||||
expect(shouldHideOnSmallScreen(layoutConfig, "secondary-info")).toBe(
|
||||
false
|
||||
);
|
||||
expect(shouldHideOnSmallScreen(layoutConfig, "decorative-elements")).toBe(
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
test("should use enhanced font styles", () => {
|
||||
const titleStyle = getAdaptiveFontStyle(layoutConfig, "title");
|
||||
const subtitleStyle = getAdaptiveFontStyle(layoutConfig, "subtitle");
|
||||
|
||||
expect(titleStyle.color).toBe("blue");
|
||||
expect(subtitleStyle.bold).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Scrollable Content Behavior", () => {
|
||||
test("should calculate scrolling needs correctly for different screen sizes", () => {
|
||||
const totalItems = 50;
|
||||
const itemHeight = 2;
|
||||
|
||||
// Small screen
|
||||
const smallScrollDimensions = getScrollableDimensions(
|
||||
screenSizes.small.layoutConfig,
|
||||
totalItems,
|
||||
itemHeight
|
||||
);
|
||||
expect(smallScrollDimensions.visibleItems).toBe(6); // Math.floor((16 - 4) / 2)
|
||||
expect(smallScrollDimensions.needsScrolling).toBe(true);
|
||||
|
||||
// Large screen
|
||||
const largeScrollDimensions = getScrollableDimensions(
|
||||
screenSizes.large.layoutConfig,
|
||||
totalItems,
|
||||
itemHeight
|
||||
);
|
||||
expect(largeScrollDimensions.visibleItems).toBe(16); // Math.floor((36 - 4) / 2)
|
||||
expect(largeScrollDimensions.needsScrolling).toBe(true);
|
||||
});
|
||||
|
||||
test("should handle cases where scrolling is not needed", () => {
|
||||
const totalItems = 5;
|
||||
const itemHeight = 1;
|
||||
|
||||
const scrollDimensions = getScrollableDimensions(
|
||||
screenSizes.large.layoutConfig,
|
||||
totalItems,
|
||||
itemHeight
|
||||
);
|
||||
expect(scrollDimensions.needsScrolling).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Text Truncation Behavior", () => {
|
||||
test("should provide different truncation lengths for different screen sizes", () => {
|
||||
const containerWidth = 60;
|
||||
|
||||
const smallTruncation = getTextTruncationLength(
|
||||
screenSizes.small.layoutConfig,
|
||||
containerWidth
|
||||
);
|
||||
const mediumTruncation = getTextTruncationLength(
|
||||
screenSizes.medium.layoutConfig,
|
||||
containerWidth
|
||||
);
|
||||
const largeTruncation = getTextTruncationLength(
|
||||
screenSizes.large.layoutConfig,
|
||||
containerWidth
|
||||
);
|
||||
|
||||
expect(smallTruncation).toBe(50); // Math.max(20, 60 - 10)
|
||||
expect(mediumTruncation).toBe(52); // Math.max(40, 60 - 8)
|
||||
expect(largeTruncation).toBe(60); // Math.max(60, 60 - 6)
|
||||
});
|
||||
|
||||
test("should enforce minimum truncation lengths", () => {
|
||||
const smallContainerWidth = 5;
|
||||
|
||||
const smallTruncation = getTextTruncationLength(
|
||||
screenSizes.small.layoutConfig,
|
||||
smallContainerWidth
|
||||
);
|
||||
const mediumTruncation = getTextTruncationLength(
|
||||
screenSizes.medium.layoutConfig,
|
||||
smallContainerWidth
|
||||
);
|
||||
const largeTruncation = getTextTruncationLength(
|
||||
screenSizes.large.layoutConfig,
|
||||
smallContainerWidth
|
||||
);
|
||||
|
||||
expect(smallTruncation).toBe(20); // Minimum enforced
|
||||
expect(mediumTruncation).toBe(40); // Minimum enforced
|
||||
expect(largeTruncation).toBe(60); // Minimum enforced
|
||||
});
|
||||
});
|
||||
|
||||
describe("Component Visibility Rules", () => {
|
||||
test("should hide appropriate components on small screens", () => {
|
||||
const componentsToHide = [
|
||||
"sidebar",
|
||||
"secondary-info",
|
||||
"decorative-elements",
|
||||
];
|
||||
const componentsToShow = [
|
||||
"main-content",
|
||||
"primary-navigation",
|
||||
"essential-info",
|
||||
];
|
||||
|
||||
componentsToHide.forEach((component) => {
|
||||
expect(
|
||||
shouldHideOnSmallScreen(screenSizes.small.layoutConfig, component)
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
componentsToShow.forEach((component) => {
|
||||
expect(
|
||||
shouldHideOnSmallScreen(screenSizes.small.layoutConfig, component)
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
test("should show all components on large screens", () => {
|
||||
const allComponents = [
|
||||
"sidebar",
|
||||
"secondary-info",
|
||||
"decorative-elements",
|
||||
"main-content",
|
||||
];
|
||||
|
||||
allComponents.forEach((component) => {
|
||||
expect(
|
||||
shouldHideOnSmallScreen(screenSizes.large.layoutConfig, component)
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
208
tests/tui/integration/shopifyService.test.js
Normal file
208
tests/tui/integration/shopifyService.test.js
Normal file
@@ -0,0 +1,208 @@
|
||||
const ShopifyService = require("../../../src/services/shopify");
|
||||
const ProductService = require("../../../src/services/product");
|
||||
const ProgressService = require("../../../src/services/progress");
|
||||
|
||||
// Mock the services to avoid actual API calls during testing
|
||||
jest.mock("../../../src/services/shopify");
|
||||
jest.mock("../../../src/services/product");
|
||||
jest.mock("../../../src/services/progress");
|
||||
|
||||
describe("TUI ShopifyService Integration", () => {
|
||||
let mockShopifyService;
|
||||
let mockProductService;
|
||||
let mockProgressService;
|
||||
|
||||
beforeEach(() => {
|
||||
// Reset all mocks
|
||||
jest.clearAllMocks();
|
||||
|
||||
// Create mock ShopifyService instance
|
||||
mockShopifyService = {
|
||||
testConnection: jest.fn(),
|
||||
getApiCallLimit: jest.fn(),
|
||||
executeQuery: jest.fn(),
|
||||
executeMutation: jest.fn(),
|
||||
executeWithRetry: jest.fn(),
|
||||
};
|
||||
|
||||
// Create mock ProductService instance
|
||||
mockProductService = {
|
||||
fetchProductsByTag: jest.fn(),
|
||||
updateProductPrices: jest.fn(),
|
||||
rollbackProductPrices: jest.fn(),
|
||||
};
|
||||
|
||||
// Create mock ProgressService instance
|
||||
mockProgressService = {
|
||||
logOperationStart: jest.fn(),
|
||||
logProductUpdate: jest.fn(),
|
||||
logCompletionSummary: jest.fn(),
|
||||
};
|
||||
|
||||
// Mock the service constructors
|
||||
ShopifyService.mockImplementation(() => mockShopifyService);
|
||||
ProductService.mockImplementation(() => mockProductService);
|
||||
ProgressService.mockImplementation(() => mockProgressService);
|
||||
});
|
||||
|
||||
describe("Service Integration", () => {
|
||||
test("should create ShopifyService instance", () => {
|
||||
const service = new ShopifyService();
|
||||
expect(service).toBeDefined();
|
||||
expect(service.testConnection).toBeDefined();
|
||||
expect(service.executeQuery).toBeDefined();
|
||||
expect(service.executeMutation).toBeDefined();
|
||||
});
|
||||
|
||||
test("should test connection through ShopifyService", async () => {
|
||||
mockShopifyService.testConnection.mockResolvedValue(true);
|
||||
|
||||
const service = new ShopifyService();
|
||||
const isConnected = await service.testConnection();
|
||||
|
||||
expect(mockShopifyService.testConnection).toHaveBeenCalled();
|
||||
expect(isConnected).toBe(true);
|
||||
});
|
||||
|
||||
test("should handle connection test failures", async () => {
|
||||
mockShopifyService.testConnection.mockRejectedValue(
|
||||
new Error("Connection failed")
|
||||
);
|
||||
|
||||
const service = new ShopifyService();
|
||||
|
||||
await expect(service.testConnection()).rejects.toThrow(
|
||||
"Connection failed"
|
||||
);
|
||||
});
|
||||
|
||||
test("should execute GraphQL queries through ShopifyService", async () => {
|
||||
const mockResponse = { data: { shop: { name: "Test Shop" } } };
|
||||
mockShopifyService.executeQuery.mockResolvedValue(mockResponse);
|
||||
|
||||
const service = new ShopifyService();
|
||||
const query = "query { shop { name } }";
|
||||
const variables = { test: "value" };
|
||||
const result = await service.executeQuery(query, variables);
|
||||
|
||||
expect(mockShopifyService.executeQuery).toHaveBeenCalledWith(
|
||||
query,
|
||||
variables
|
||||
);
|
||||
expect(result).toEqual(mockResponse);
|
||||
});
|
||||
|
||||
test("should execute GraphQL mutations through ShopifyService", async () => {
|
||||
const mockResponse = { data: { productUpdate: { id: "123" } } };
|
||||
mockShopifyService.executeMutation.mockResolvedValue(mockResponse);
|
||||
|
||||
const service = new ShopifyService();
|
||||
const mutation = "mutation { productUpdate(input: {}) { id } }";
|
||||
const variables = { input: { id: "123" } };
|
||||
const result = await service.executeMutation(mutation, variables);
|
||||
|
||||
expect(mockShopifyService.executeMutation).toHaveBeenCalledWith(
|
||||
mutation,
|
||||
variables
|
||||
);
|
||||
expect(result).toEqual(mockResponse);
|
||||
});
|
||||
|
||||
test("should execute operations with retry logic", async () => {
|
||||
const mockOperation = jest.fn().mockResolvedValue("success");
|
||||
const mockLogger = { log: jest.fn() };
|
||||
mockShopifyService.executeWithRetry.mockResolvedValue("success");
|
||||
|
||||
const service = new ShopifyService();
|
||||
const result = await service.executeWithRetry(mockOperation, mockLogger);
|
||||
|
||||
expect(mockShopifyService.executeWithRetry).toHaveBeenCalledWith(
|
||||
mockOperation,
|
||||
mockLogger
|
||||
);
|
||||
expect(result).toBe("success");
|
||||
});
|
||||
|
||||
test("should get API call limit information", async () => {
|
||||
const mockLimitInfo = {
|
||||
requestedQueryCost: 10,
|
||||
actualQueryCost: 8,
|
||||
throttleStatus: { maximumAvailable: 1000, currentlyAvailable: 992 },
|
||||
};
|
||||
mockShopifyService.getApiCallLimit.mockResolvedValue(mockLimitInfo);
|
||||
|
||||
const service = new ShopifyService();
|
||||
const limitInfo = await service.getApiCallLimit();
|
||||
|
||||
expect(mockShopifyService.getApiCallLimit).toHaveBeenCalled();
|
||||
expect(limitInfo).toEqual(mockLimitInfo);
|
||||
});
|
||||
|
||||
test("should handle API call limit retrieval errors gracefully", async () => {
|
||||
mockShopifyService.getApiCallLimit.mockRejectedValue(
|
||||
new Error("API limit error")
|
||||
);
|
||||
|
||||
const service = new ShopifyService();
|
||||
|
||||
await expect(service.getApiCallLimit()).rejects.toThrow(
|
||||
"API limit error"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Service Method Integration", () => {
|
||||
test("should integrate all service methods correctly", () => {
|
||||
const shopifyService = new ShopifyService();
|
||||
const productService = new ProductService();
|
||||
const progressService = new ProgressService();
|
||||
|
||||
// Verify all services are created
|
||||
expect(shopifyService).toBeDefined();
|
||||
expect(productService).toBeDefined();
|
||||
expect(progressService).toBeDefined();
|
||||
|
||||
// Verify ShopifyService methods
|
||||
expect(typeof shopifyService.testConnection).toBe("function");
|
||||
expect(typeof shopifyService.executeQuery).toBe("function");
|
||||
expect(typeof shopifyService.executeMutation).toBe("function");
|
||||
expect(typeof shopifyService.executeWithRetry).toBe("function");
|
||||
expect(typeof shopifyService.getApiCallLimit).toBe("function");
|
||||
|
||||
// Verify ProductService methods
|
||||
expect(typeof productService.fetchProductsByTag).toBe("function");
|
||||
expect(typeof productService.updateProductPrices).toBe("function");
|
||||
expect(typeof productService.rollbackProductPrices).toBe("function");
|
||||
|
||||
// Verify ProgressService methods
|
||||
expect(typeof progressService.logOperationStart).toBe("function");
|
||||
expect(typeof progressService.logProductUpdate).toBe("function");
|
||||
expect(typeof progressService.logCompletionSummary).toBe("function");
|
||||
});
|
||||
|
||||
test("should maintain service API compatibility", async () => {
|
||||
// Test that services maintain their expected API
|
||||
mockShopifyService.testConnection.mockResolvedValue(true);
|
||||
mockProductService.fetchProductsByTag.mockResolvedValue([]);
|
||||
mockProgressService.logOperationStart.mockResolvedValue();
|
||||
|
||||
const shopifyService = new ShopifyService();
|
||||
const productService = new ProductService();
|
||||
const progressService = new ProgressService();
|
||||
|
||||
// Test ShopifyService API
|
||||
const connectionResult = await shopifyService.testConnection();
|
||||
expect(connectionResult).toBe(true);
|
||||
|
||||
// Test ProductService API
|
||||
const products = await productService.fetchProductsByTag("test-tag");
|
||||
expect(Array.isArray(products)).toBe(true);
|
||||
|
||||
// Test ProgressService API
|
||||
await progressService.logOperationStart({ targetTag: "test" });
|
||||
expect(mockProgressService.logOperationStart).toHaveBeenCalledWith({
|
||||
targetTag: "test",
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user