462 lines
13 KiB
JavaScript
462 lines
13 KiB
JavaScript
const Logger = require("../../src/utils/logger");
|
|
const ProgressService = require("../../src/services/progress");
|
|
|
|
// Mock the ProgressService
|
|
jest.mock("../../src/services/progress");
|
|
|
|
describe("Logger", () => {
|
|
let logger;
|
|
let mockProgressService;
|
|
let consoleSpy;
|
|
|
|
beforeEach(() => {
|
|
// Create mock progress service
|
|
mockProgressService = {
|
|
logOperationStart: jest.fn(),
|
|
logRollbackStart: jest.fn(),
|
|
logProductUpdate: jest.fn(),
|
|
logRollbackUpdate: jest.fn(),
|
|
logCompletionSummary: jest.fn(),
|
|
logRollbackSummary: jest.fn(),
|
|
logError: jest.fn(),
|
|
logErrorAnalysis: jest.fn(),
|
|
};
|
|
|
|
// Mock the ProgressService constructor
|
|
ProgressService.mockImplementation(() => mockProgressService);
|
|
|
|
logger = new Logger();
|
|
|
|
// Spy on console methods
|
|
consoleSpy = {
|
|
log: jest.spyOn(console, "log").mockImplementation(() => {}),
|
|
warn: jest.spyOn(console, "warn").mockImplementation(() => {}),
|
|
error: jest.spyOn(console, "error").mockImplementation(() => {}),
|
|
};
|
|
});
|
|
|
|
afterEach(() => {
|
|
jest.clearAllMocks();
|
|
consoleSpy.log.mockRestore();
|
|
consoleSpy.warn.mockRestore();
|
|
consoleSpy.error.mockRestore();
|
|
});
|
|
|
|
describe("Rollback Logging Methods", () => {
|
|
describe("logRollbackStart", () => {
|
|
it("should log rollback operation start to console and progress file", async () => {
|
|
const config = {
|
|
targetTag: "test-tag",
|
|
shopDomain: "test-shop.myshopify.com",
|
|
};
|
|
|
|
await logger.logRollbackStart(config);
|
|
|
|
// Check console output
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining(
|
|
"Starting price rollback operation with configuration:"
|
|
)
|
|
);
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining("Target Tag: test-tag")
|
|
);
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining("Operation Mode: rollback")
|
|
);
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining("Shop Domain: test-shop.myshopify.com")
|
|
);
|
|
|
|
// Check progress service was called
|
|
expect(mockProgressService.logRollbackStart).toHaveBeenCalledWith(
|
|
config
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("logRollbackUpdate", () => {
|
|
it("should log successful rollback operations to console and progress file", async () => {
|
|
const entry = {
|
|
productTitle: "Test Product",
|
|
productId: "gid://shopify/Product/123",
|
|
variantId: "gid://shopify/ProductVariant/456",
|
|
oldPrice: 1000.0,
|
|
compareAtPrice: 750.0,
|
|
newPrice: 750.0,
|
|
};
|
|
|
|
await logger.logRollbackUpdate(entry);
|
|
|
|
// Check console output contains rollback-specific formatting
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining("🔄")
|
|
);
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining('Rolled back "Test Product"')
|
|
);
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining("Price: 1000 → 750")
|
|
);
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining("from Compare At: 750")
|
|
);
|
|
|
|
// Check progress service was called
|
|
expect(mockProgressService.logRollbackUpdate).toHaveBeenCalledWith(
|
|
entry
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("logRollbackSummary", () => {
|
|
it("should log rollback completion summary to console and progress file", async () => {
|
|
const summary = {
|
|
totalProducts: 5,
|
|
totalVariants: 8,
|
|
eligibleVariants: 6,
|
|
successfulRollbacks: 5,
|
|
failedRollbacks: 1,
|
|
skippedVariants: 2,
|
|
startTime: new Date(Date.now() - 30000), // 30 seconds ago
|
|
};
|
|
|
|
await logger.logRollbackSummary(summary);
|
|
|
|
// Check console output contains rollback-specific formatting
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining("ROLLBACK OPERATION COMPLETE")
|
|
);
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining("Total Products Processed: 5")
|
|
);
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining("Total Variants Processed: 8")
|
|
);
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining("Eligible Variants: 6")
|
|
);
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining("Successful Rollbacks: ")
|
|
);
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining("Failed Rollbacks: ")
|
|
);
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining("Skipped Variants: ")
|
|
);
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining("no compare-at price")
|
|
);
|
|
|
|
// Check progress service was called
|
|
expect(mockProgressService.logRollbackSummary).toHaveBeenCalledWith(
|
|
summary
|
|
);
|
|
});
|
|
|
|
it("should handle zero failed rollbacks without red coloring", async () => {
|
|
const summary = {
|
|
totalProducts: 3,
|
|
totalVariants: 5,
|
|
eligibleVariants: 5,
|
|
successfulRollbacks: 5,
|
|
failedRollbacks: 0,
|
|
skippedVariants: 0,
|
|
startTime: new Date(Date.now() - 15000),
|
|
};
|
|
|
|
await logger.logRollbackSummary(summary);
|
|
|
|
// Should show failed rollbacks without red coloring when zero
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining("Failed Rollbacks: 0")
|
|
);
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining("Skipped Variants: 0")
|
|
);
|
|
});
|
|
|
|
it("should show colored output for failed rollbacks and skipped variants when greater than zero", async () => {
|
|
const summary = {
|
|
totalProducts: 5,
|
|
totalVariants: 8,
|
|
eligibleVariants: 6,
|
|
successfulRollbacks: 4,
|
|
failedRollbacks: 2,
|
|
skippedVariants: 2,
|
|
startTime: new Date(Date.now() - 45000),
|
|
};
|
|
|
|
await logger.logRollbackSummary(summary);
|
|
|
|
// Should show colored output for non-zero values
|
|
const logCalls = consoleSpy.log.mock.calls.map((call) => call[0]);
|
|
const failedRollbacksCall = logCalls.find((call) =>
|
|
call.includes("Failed Rollbacks:")
|
|
);
|
|
const skippedVariantsCall = logCalls.find((call) =>
|
|
call.includes("Skipped Variants:")
|
|
);
|
|
|
|
expect(failedRollbacksCall).toContain("\x1b[31m"); // Red color code
|
|
expect(skippedVariantsCall).toContain("\x1b[33m"); // Yellow color code
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("Rollback vs Update Distinction", () => {
|
|
it("should distinguish rollback logs from update logs in console output", async () => {
|
|
const updateEntry = {
|
|
productTitle: "Test Product",
|
|
oldPrice: 750.0,
|
|
newPrice: 1000.0,
|
|
compareAtPrice: 1000.0,
|
|
};
|
|
|
|
const rollbackEntry = {
|
|
productTitle: "Test Product",
|
|
oldPrice: 1000.0,
|
|
compareAtPrice: 750.0,
|
|
newPrice: 750.0,
|
|
};
|
|
|
|
await logger.logProductUpdate(updateEntry);
|
|
await logger.logRollbackUpdate(rollbackEntry);
|
|
|
|
const logCalls = consoleSpy.log.mock.calls.map((call) => call[0]);
|
|
|
|
// Update should use checkmark emoji
|
|
const updateCall = logCalls.find((call) => call.includes("Updated"));
|
|
expect(updateCall).toContain("✅");
|
|
|
|
// Rollback should use rollback emoji
|
|
const rollbackCall = logCalls.find((call) =>
|
|
call.includes("Rolled back")
|
|
);
|
|
expect(rollbackCall).toContain("🔄");
|
|
});
|
|
|
|
it("should call different progress service methods for updates vs rollbacks", async () => {
|
|
const updateEntry = {
|
|
productTitle: "Test",
|
|
oldPrice: 750,
|
|
newPrice: 1000,
|
|
};
|
|
const rollbackEntry = {
|
|
productTitle: "Test",
|
|
oldPrice: 1000,
|
|
newPrice: 750,
|
|
compareAtPrice: 750,
|
|
};
|
|
|
|
await logger.logProductUpdate(updateEntry);
|
|
await logger.logRollbackUpdate(rollbackEntry);
|
|
|
|
expect(mockProgressService.logProductUpdate).toHaveBeenCalledWith(
|
|
updateEntry
|
|
);
|
|
expect(mockProgressService.logRollbackUpdate).toHaveBeenCalledWith(
|
|
rollbackEntry
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("Error Handling", () => {
|
|
it("should handle progress service errors gracefully", async () => {
|
|
mockProgressService.logRollbackStart.mockRejectedValue(
|
|
new Error("Progress service error")
|
|
);
|
|
|
|
const config = {
|
|
targetTag: "test-tag",
|
|
shopDomain: "test-shop.myshopify.com",
|
|
};
|
|
|
|
// Should not throw even if progress service fails
|
|
await expect(logger.logRollbackStart(config)).resolves.not.toThrow();
|
|
|
|
// Console output should still work
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining("Starting price rollback operation")
|
|
);
|
|
});
|
|
|
|
it("should handle rollback update logging errors gracefully", async () => {
|
|
mockProgressService.logRollbackUpdate.mockRejectedValue(
|
|
new Error("Progress service error")
|
|
);
|
|
|
|
const entry = {
|
|
productTitle: "Test Product",
|
|
oldPrice: 1000,
|
|
newPrice: 750,
|
|
compareAtPrice: 750,
|
|
};
|
|
|
|
// Should not throw even if progress service fails
|
|
await expect(logger.logRollbackUpdate(entry)).resolves.not.toThrow();
|
|
|
|
// Console output should still work
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining("Rolled back")
|
|
);
|
|
});
|
|
|
|
it("should handle rollback summary logging errors gracefully", async () => {
|
|
mockProgressService.logRollbackSummary.mockRejectedValue(
|
|
new Error("Progress service error")
|
|
);
|
|
|
|
const summary = {
|
|
totalProducts: 5,
|
|
successfulRollbacks: 4,
|
|
failedRollbacks: 1,
|
|
skippedVariants: 0,
|
|
startTime: new Date(),
|
|
};
|
|
|
|
// Should not throw even if progress service fails
|
|
await expect(logger.logRollbackSummary(summary)).resolves.not.toThrow();
|
|
|
|
// Console output should still work
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining("ROLLBACK OPERATION COMPLETE")
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("Existing Logger Methods", () => {
|
|
describe("Basic logging methods", () => {
|
|
it("should log info messages to console", async () => {
|
|
await logger.info("Test info message");
|
|
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining("Test info message")
|
|
);
|
|
});
|
|
|
|
it("should log warning messages to console", async () => {
|
|
await logger.warning("Test warning message");
|
|
|
|
expect(consoleSpy.warn).toHaveBeenCalledWith(
|
|
expect.stringContaining("Test warning message")
|
|
);
|
|
});
|
|
|
|
it("should log error messages to console", async () => {
|
|
await logger.error("Test error message");
|
|
|
|
expect(consoleSpy.error).toHaveBeenCalledWith(
|
|
expect.stringContaining("Test error message")
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("Operation start logging", () => {
|
|
it("should log operation start for update mode", async () => {
|
|
const config = {
|
|
targetTag: "test-tag",
|
|
priceAdjustmentPercentage: 10,
|
|
shopDomain: "test-shop.myshopify.com",
|
|
};
|
|
|
|
await logger.logOperationStart(config);
|
|
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining("Starting price update operation")
|
|
);
|
|
expect(mockProgressService.logOperationStart).toHaveBeenCalledWith(
|
|
config
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("Product update logging", () => {
|
|
it("should log product updates", async () => {
|
|
const entry = {
|
|
productTitle: "Test Product",
|
|
oldPrice: 100,
|
|
newPrice: 110,
|
|
compareAtPrice: 100,
|
|
};
|
|
|
|
await logger.logProductUpdate(entry);
|
|
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining("Updated")
|
|
);
|
|
expect(mockProgressService.logProductUpdate).toHaveBeenCalledWith(
|
|
entry
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("Completion summary logging", () => {
|
|
it("should log completion summary", async () => {
|
|
const summary = {
|
|
totalProducts: 5,
|
|
successfulUpdates: 4,
|
|
failedUpdates: 1,
|
|
startTime: new Date(),
|
|
};
|
|
|
|
await logger.logCompletionSummary(summary);
|
|
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining("OPERATION COMPLETE")
|
|
);
|
|
expect(mockProgressService.logCompletionSummary).toHaveBeenCalledWith(
|
|
summary
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("Error logging", () => {
|
|
it("should log product errors", async () => {
|
|
const errorEntry = {
|
|
productTitle: "Test Product",
|
|
errorMessage: "Test error",
|
|
};
|
|
|
|
await logger.logProductError(errorEntry);
|
|
|
|
expect(mockProgressService.logError).toHaveBeenCalledWith(errorEntry);
|
|
});
|
|
|
|
it("should log error analysis", async () => {
|
|
const errors = [
|
|
{ errorMessage: "Error 1" },
|
|
{ errorMessage: "Error 2" },
|
|
];
|
|
const summary = { totalProducts: 2 };
|
|
|
|
await logger.logErrorAnalysis(errors, summary);
|
|
|
|
expect(mockProgressService.logErrorAnalysis).toHaveBeenCalledWith(
|
|
errors,
|
|
summary
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("Product count logging", () => {
|
|
it("should log product count", async () => {
|
|
await logger.logProductCount(5);
|
|
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining("Found 5 products")
|
|
);
|
|
});
|
|
|
|
it("should handle zero products", async () => {
|
|
await logger.logProductCount(0);
|
|
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining("Found 0 products")
|
|
);
|
|
});
|
|
});
|
|
});
|
|
});
|