Implemented Rollback Functionality

This commit is contained in:
2025-08-06 15:18:44 -05:00
parent d741dd5466
commit 78818793f2
20 changed files with 6365 additions and 74 deletions

View File

@@ -109,6 +109,47 @@ describe("ProgressService", () => {
});
});
describe("logRollbackStart", () => {
test("should create progress file and log rollback operation start", async () => {
const config = {
targetTag: "rollback-tag",
};
await progressService.logRollbackStart(config);
// Check that file was created
const content = await fs.readFile(testFilePath, "utf8");
expect(content).toContain("# Shopify Price Update Progress Log");
expect(content).toContain("## Price Rollback Operation -");
expect(content).toContain("Target Tag: rollback-tag");
expect(content).toContain("Operation Mode: rollback");
expect(content).toContain("**Configuration:**");
expect(content).toContain("**Progress:**");
});
test("should distinguish rollback from update operations in logs", async () => {
const updateConfig = {
targetTag: "update-tag",
priceAdjustmentPercentage: 10,
};
const rollbackConfig = {
targetTag: "rollback-tag",
};
await progressService.logOperationStart(updateConfig);
await progressService.logRollbackStart(rollbackConfig);
const content = await fs.readFile(testFilePath, "utf8");
expect(content).toContain("## Price Update Operation -");
expect(content).toContain("Price Adjustment: 10%");
expect(content).toContain("## Price Rollback Operation -");
expect(content).toContain("Operation Mode: rollback");
});
});
describe("logProductUpdate", () => {
test("should log successful product update", async () => {
// First create the file
@@ -182,6 +223,97 @@ describe("ProgressService", () => {
});
});
describe("logRollbackUpdate", () => {
test("should log successful rollback operation", async () => {
// First create the file
await progressService.logRollbackStart({
targetTag: "rollback-test",
});
const entry = {
productId: "gid://shopify/Product/123456789",
productTitle: "Rollback Test Product",
variantId: "gid://shopify/ProductVariant/987654321",
oldPrice: 1000.0,
compareAtPrice: 750.0,
newPrice: 750.0,
};
await progressService.logRollbackUpdate(entry);
const content = await fs.readFile(testFilePath, "utf8");
expect(content).toContain(
"🔄 **Rollback Test Product** (gid://shopify/Product/123456789)"
);
expect(content).toContain(
"Variant: gid://shopify/ProductVariant/987654321"
);
expect(content).toContain("Price: $1000 → $750 (from Compare At: $750)");
expect(content).toContain("Rolled back:");
});
test("should distinguish rollback from update entries", async () => {
await progressService.logRollbackStart({
targetTag: "test",
});
const updateEntry = {
productId: "gid://shopify/Product/123",
productTitle: "Update Product",
variantId: "gid://shopify/ProductVariant/456",
oldPrice: 750.0,
newPrice: 1000.0,
};
const rollbackEntry = {
productId: "gid://shopify/Product/789",
productTitle: "Rollback Product",
variantId: "gid://shopify/ProductVariant/012",
oldPrice: 1000.0,
compareAtPrice: 750.0,
newPrice: 750.0,
};
await progressService.logProductUpdate(updateEntry);
await progressService.logRollbackUpdate(rollbackEntry);
const content = await fs.readFile(testFilePath, "utf8");
// Update entry should use checkmark
expect(content).toContain("✅ **Update Product**");
expect(content).toContain("Updated:");
// Rollback entry should use rollback emoji
expect(content).toContain("🔄 **Rollback Product**");
expect(content).toContain("from Compare At:");
expect(content).toContain("Rolled back:");
});
test("should handle products with special characters in rollback", async () => {
await progressService.logRollbackStart({
targetTag: "test",
});
const entry = {
productId: "gid://shopify/Product/123",
productTitle: 'Rollback Product with "Quotes" & Special Chars!',
variantId: "gid://shopify/ProductVariant/456",
oldPrice: 500.0,
compareAtPrice: 400.0,
newPrice: 400.0,
};
await progressService.logRollbackUpdate(entry);
const content = await fs.readFile(testFilePath, "utf8");
expect(content).toContain(
'**Rollback Product with "Quotes" & Special Chars!**'
);
});
});
describe("logError", () => {
test("should log error with all details", async () => {
await progressService.logOperationStart({
@@ -325,6 +457,123 @@ describe("ProgressService", () => {
});
});
describe("logRollbackSummary", () => {
test("should log rollback completion summary with all statistics", async () => {
await progressService.logRollbackStart({
targetTag: "rollback-test",
});
const startTime = new Date(Date.now() - 8000); // 8 seconds ago
const summary = {
totalProducts: 5,
totalVariants: 8,
eligibleVariants: 6,
successfulRollbacks: 5,
failedRollbacks: 1,
skippedVariants: 2,
startTime: startTime,
};
await progressService.logRollbackSummary(summary);
const content = await fs.readFile(testFilePath, "utf8");
expect(content).toContain("**Rollback Summary:**");
expect(content).toContain("Total Products Processed: 5");
expect(content).toContain("Total Variants Processed: 8");
expect(content).toContain("Eligible Variants: 6");
expect(content).toContain("Successful Rollbacks: 5");
expect(content).toContain("Failed Rollbacks: 1");
expect(content).toContain("Skipped Variants: 2 (no compare-at price)");
expect(content).toContain("Duration: 8 seconds");
expect(content).toContain("Completed:");
expect(content).toContain("---");
});
test("should handle rollback summary without start time", async () => {
await progressService.logRollbackStart({
targetTag: "test",
});
const summary = {
totalProducts: 3,
totalVariants: 5,
eligibleVariants: 5,
successfulRollbacks: 5,
failedRollbacks: 0,
skippedVariants: 0,
};
await progressService.logRollbackSummary(summary);
const content = await fs.readFile(testFilePath, "utf8");
expect(content).toContain("Duration: Unknown seconds");
});
test("should distinguish rollback summary from update summary", async () => {
await progressService.logRollbackStart({
targetTag: "test",
});
const updateSummary = {
totalProducts: 5,
successfulUpdates: 4,
failedUpdates: 1,
startTime: new Date(Date.now() - 5000),
};
const rollbackSummary = {
totalProducts: 3,
totalVariants: 6,
eligibleVariants: 4,
successfulRollbacks: 3,
failedRollbacks: 1,
skippedVariants: 2,
startTime: new Date(Date.now() - 3000),
};
await progressService.logCompletionSummary(updateSummary);
await progressService.logRollbackSummary(rollbackSummary);
const content = await fs.readFile(testFilePath, "utf8");
// Should contain both summary types
expect(content).toContain("**Summary:**");
expect(content).toContain("Successful Updates: 4");
expect(content).toContain("**Rollback Summary:**");
expect(content).toContain("Successful Rollbacks: 3");
expect(content).toContain("Skipped Variants: 2 (no compare-at price)");
});
test("should handle zero rollback statistics", async () => {
await progressService.logRollbackStart({
targetTag: "test",
});
const summary = {
totalProducts: 0,
totalVariants: 0,
eligibleVariants: 0,
successfulRollbacks: 0,
failedRollbacks: 0,
skippedVariants: 0,
startTime: new Date(),
};
await progressService.logRollbackSummary(summary);
const content = await fs.readFile(testFilePath, "utf8");
expect(content).toContain("Total Products Processed: 0");
expect(content).toContain("Total Variants Processed: 0");
expect(content).toContain("Eligible Variants: 0");
expect(content).toContain("Successful Rollbacks: 0");
expect(content).toContain("Failed Rollbacks: 0");
expect(content).toContain("Skipped Variants: 0");
});
});
describe("categorizeError", () => {
test("should categorize rate limiting errors", () => {
const testCases = [