const { loadEnvironmentConfig } = require("../../src/config/environment"); describe("Environment Configuration", () => { // Store original environment variables const originalEnv = process.env; beforeEach(() => { // Reset environment variables before each test jest.resetModules(); process.env = { ...originalEnv }; // Clear the specific environment variables we're testing delete process.env.SHOPIFY_SHOP_DOMAIN; delete process.env.SHOPIFY_ACCESS_TOKEN; delete process.env.TARGET_TAG; delete process.env.PRICE_ADJUSTMENT_PERCENTAGE; delete process.env.OPERATION_MODE; delete process.env.SCHEDULED_EXECUTION_TIME; }); afterAll(() => { // Restore original environment variables process.env = originalEnv; }); describe("loadEnvironmentConfig", () => { test("should load valid configuration successfully", () => { // Set up valid environment variables process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.TARGET_TAG = "sale"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "10"; const config = loadEnvironmentConfig(); expect(config).toEqual({ shopDomain: "test-shop.myshopify.com", accessToken: "shpat_1234567890abcdef", targetTag: "sale", priceAdjustmentPercentage: 10, operationMode: "update", scheduledExecutionTime: null, isScheduled: false, }); }); test("should handle negative percentage correctly", () => { process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.TARGET_TAG = "clearance"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "-20"; const config = loadEnvironmentConfig(); expect(config.priceAdjustmentPercentage).toBe(-20); }); test("should handle decimal percentage correctly", () => { process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.TARGET_TAG = "premium"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "5.5"; const config = loadEnvironmentConfig(); expect(config.priceAdjustmentPercentage).toBe(5.5); }); test("should trim whitespace from string values", () => { process.env.SHOPIFY_SHOP_DOMAIN = " test-shop.myshopify.com "; process.env.SHOPIFY_ACCESS_TOKEN = " shpat_1234567890abcdef "; process.env.TARGET_TAG = " sale "; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "10"; const config = loadEnvironmentConfig(); expect(config.shopDomain).toBe("test-shop.myshopify.com"); expect(config.accessToken).toBe("shpat_1234567890abcdef"); expect(config.targetTag).toBe("sale"); }); test("should accept custom domain format", () => { process.env.SHOPIFY_SHOP_DOMAIN = "custom-domain.com"; process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.TARGET_TAG = "sale"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "10"; const config = loadEnvironmentConfig(); expect(config.shopDomain).toBe("custom-domain.com"); }); describe("Missing environment variables", () => { test("should throw error when SHOPIFY_SHOP_DOMAIN is missing", () => { process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.TARGET_TAG = "sale"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "10"; expect(() => loadEnvironmentConfig()).toThrow( "Missing required environment variables: SHOPIFY_SHOP_DOMAIN" ); }); test("should throw error when SHOPIFY_ACCESS_TOKEN is missing", () => { process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; process.env.TARGET_TAG = "sale"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "10"; expect(() => loadEnvironmentConfig()).toThrow( "Missing required environment variables: SHOPIFY_ACCESS_TOKEN" ); }); test("should throw error when TARGET_TAG is missing", () => { process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "10"; expect(() => loadEnvironmentConfig()).toThrow( "Missing required environment variables: TARGET_TAG" ); }); test("should throw error when PRICE_ADJUSTMENT_PERCENTAGE is missing", () => { process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.TARGET_TAG = "sale"; expect(() => loadEnvironmentConfig()).toThrow( "Missing required environment variables: PRICE_ADJUSTMENT_PERCENTAGE" ); }); test("should throw error when multiple variables are missing", () => { process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; expect(() => loadEnvironmentConfig()).toThrow( "Missing required environment variables: SHOPIFY_ACCESS_TOKEN, TARGET_TAG, PRICE_ADJUSTMENT_PERCENTAGE" ); }); test("should throw error when variables are empty strings", () => { process.env.SHOPIFY_SHOP_DOMAIN = ""; process.env.SHOPIFY_ACCESS_TOKEN = ""; process.env.TARGET_TAG = ""; process.env.PRICE_ADJUSTMENT_PERCENTAGE = ""; expect(() => loadEnvironmentConfig()).toThrow( "Missing required environment variables" ); }); test("should throw error when variables are whitespace only", () => { process.env.SHOPIFY_SHOP_DOMAIN = " "; process.env.SHOPIFY_ACCESS_TOKEN = " "; process.env.TARGET_TAG = " "; process.env.PRICE_ADJUSTMENT_PERCENTAGE = " "; expect(() => loadEnvironmentConfig()).toThrow( "Missing required environment variables" ); }); }); describe("Invalid environment variable values", () => { test("should throw error for invalid percentage", () => { process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.TARGET_TAG = "sale"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "invalid"; expect(() => loadEnvironmentConfig()).toThrow( 'Invalid PRICE_ADJUSTMENT_PERCENTAGE: "invalid". Must be a valid number.' ); }); test("should throw error for invalid shop domain", () => { process.env.SHOPIFY_SHOP_DOMAIN = "invalid-domain"; process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.TARGET_TAG = "sale"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "10"; expect(() => loadEnvironmentConfig()).toThrow( 'Invalid SHOPIFY_SHOP_DOMAIN: "invalid-domain". Must be a valid Shopify domain' ); }); test("should throw error for short access token", () => { process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; process.env.SHOPIFY_ACCESS_TOKEN = "short"; process.env.TARGET_TAG = "sale"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "10"; expect(() => loadEnvironmentConfig()).toThrow( "Invalid SHOPIFY_ACCESS_TOKEN: Token appears to be too short" ); }); test("should throw error for whitespace-only target tag", () => { process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.TARGET_TAG = " "; // This will be caught by the missing variables check process.env.PRICE_ADJUSTMENT_PERCENTAGE = "10"; expect(() => loadEnvironmentConfig()).toThrow( "Missing required environment variables: TARGET_TAG" ); }); }); describe("Edge cases", () => { test("should handle zero percentage", () => { process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.TARGET_TAG = "no-change"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "0"; const config = loadEnvironmentConfig(); expect(config.priceAdjustmentPercentage).toBe(0); }); test("should handle very large percentage", () => { process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.TARGET_TAG = "huge-increase"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "1000"; const config = loadEnvironmentConfig(); expect(config.priceAdjustmentPercentage).toBe(1000); }); test("should handle very small decimal percentage", () => { process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.TARGET_TAG = "tiny-adjustment"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "0.01"; const config = loadEnvironmentConfig(); expect(config.priceAdjustmentPercentage).toBe(0.01); }); test("should handle tag with special characters", () => { process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.TARGET_TAG = "sale-2024_special!"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "10"; const config = loadEnvironmentConfig(); expect(config.targetTag).toBe("sale-2024_special!"); }); }); describe("Operation Mode", () => { test("should default to 'update' when OPERATION_MODE is not set", () => { process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.TARGET_TAG = "sale"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "10"; // OPERATION_MODE is not set const config = loadEnvironmentConfig(); expect(config.operationMode).toBe("update"); }); test("should accept 'update' operation mode", () => { process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.TARGET_TAG = "sale"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "10"; process.env.OPERATION_MODE = "update"; const config = loadEnvironmentConfig(); expect(config.operationMode).toBe("update"); }); test("should accept 'rollback' operation mode", () => { process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.TARGET_TAG = "sale"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "10"; process.env.OPERATION_MODE = "rollback"; const config = loadEnvironmentConfig(); expect(config.operationMode).toBe("rollback"); }); test("should throw error for invalid operation mode", () => { process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.TARGET_TAG = "sale"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "10"; process.env.OPERATION_MODE = "invalid"; expect(() => loadEnvironmentConfig()).toThrow( 'Invalid OPERATION_MODE: "invalid". Must be either "update" or "rollback".' ); }); test("should throw error for empty operation mode", () => { process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.TARGET_TAG = "sale"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "10"; process.env.OPERATION_MODE = ""; const config = loadEnvironmentConfig(); // Empty string should default to "update" expect(config.operationMode).toBe("update"); }); test("should handle case sensitivity in operation mode", () => { process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.TARGET_TAG = "sale"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "10"; process.env.OPERATION_MODE = "UPDATE"; expect(() => loadEnvironmentConfig()).toThrow( 'Invalid OPERATION_MODE: "UPDATE". Must be either "update" or "rollback".' ); }); test("should handle whitespace in operation mode", () => { process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.TARGET_TAG = "sale"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "10"; process.env.OPERATION_MODE = " rollback "; expect(() => loadEnvironmentConfig()).toThrow( 'Invalid OPERATION_MODE: " rollback ". Must be either "update" or "rollback".' ); }); test("should handle null operation mode", () => { process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.TARGET_TAG = "sale"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "10"; process.env.OPERATION_MODE = null; const config = loadEnvironmentConfig(); // Null should default to "update" expect(config.operationMode).toBe("update"); }); test("should handle undefined operation mode", () => { process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.TARGET_TAG = "sale"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "10"; process.env.OPERATION_MODE = undefined; const config = loadEnvironmentConfig(); // Undefined should default to "update" expect(config.operationMode).toBe("update"); }); }); describe("Rollback Mode Specific Validation", () => { test("should validate rollback mode with all required variables", () => { process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.TARGET_TAG = "sale"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "10"; process.env.OPERATION_MODE = "rollback"; const config = loadEnvironmentConfig(); expect(config).toEqual({ shopDomain: "test-shop.myshopify.com", accessToken: "shpat_1234567890abcdef", targetTag: "sale", priceAdjustmentPercentage: 10, operationMode: "rollback", scheduledExecutionTime: null, isScheduled: false, }); }); test("should validate rollback mode even with zero percentage", () => { process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.TARGET_TAG = "sale"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "0"; process.env.OPERATION_MODE = "rollback"; const config = loadEnvironmentConfig(); expect(config.operationMode).toBe("rollback"); expect(config.priceAdjustmentPercentage).toBe(0); }); test("should validate rollback mode with negative percentage", () => { process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.TARGET_TAG = "sale"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "-20"; process.env.OPERATION_MODE = "rollback"; const config = loadEnvironmentConfig(); expect(config.operationMode).toBe("rollback"); expect(config.priceAdjustmentPercentage).toBe(-20); }); }); describe("Scheduled Execution Time", () => { beforeEach(() => { // Set up valid base environment variables process.env.SHOPIFY_SHOP_DOMAIN = "test-shop.myshopify.com"; process.env.SHOPIFY_ACCESS_TOKEN = "shpat_1234567890abcdef"; process.env.TARGET_TAG = "sale"; process.env.PRICE_ADJUSTMENT_PERCENTAGE = "10"; }); test("should handle missing SCHEDULED_EXECUTION_TIME (backward compatibility)", () => { // SCHEDULED_EXECUTION_TIME is not set const config = loadEnvironmentConfig(); expect(config.scheduledExecutionTime).toBeNull(); expect(config.isScheduled).toBe(false); }); test("should handle empty SCHEDULED_EXECUTION_TIME", () => { process.env.SCHEDULED_EXECUTION_TIME = ""; const config = loadEnvironmentConfig(); expect(config.scheduledExecutionTime).toBeNull(); expect(config.isScheduled).toBe(false); }); test("should accept valid ISO 8601 datetime with Z timezone", () => { const futureTime = "2030-01-15T12:00:00Z"; process.env.SCHEDULED_EXECUTION_TIME = futureTime; const config = loadEnvironmentConfig(); expect(config.scheduledExecutionTime).toEqual(new Date(futureTime)); expect(config.isScheduled).toBe(true); }); test("should throw error for invalid datetime format", () => { process.env.SCHEDULED_EXECUTION_TIME = "2024-01-15 12:00:00"; expect(() => loadEnvironmentConfig()).toThrow( "Invalid SCHEDULED_EXECUTION_TIME format" ); }); test("should throw error for past datetime", () => { const pastTime = "2020-01-15T09:00:00Z"; // Clearly in the past process.env.SCHEDULED_EXECUTION_TIME = pastTime; expect(() => loadEnvironmentConfig()).toThrow("must be in the future"); }); }); }); });