#!/usr/bin/env node /** * Unit Tests for Helper Functions * * Tests for newly added helper functions to ensure code quality * and prevent regressions. */ import { strict as assert } from "assert"; /** * Helper function to generate safe filename * Mirrors the implementation in bin/utils/name.ts */ function generateSafeFilename(name) { return name .replace(/[<>:"/\\|?*]/g, "_") .replace(/\s+/g, "_") .replace(/\.+$/g, "") .slice(0, 255); } /** * Helper function to generate safe lowercase app name for file paths * Mirrors the implementation in bin/helpers/merge.ts */ function getSafeAppName(name) { return generateSafeFilename(name).toLowerCase(); } /** * Test suite for getSafeAppName() */ export function testGetSafeAppName() { const tests = [ // Basic cases { input: "MyApp", expected: "myapp", description: "Simple name" }, { input: "My App", expected: "my_app", description: "Name with space" }, { input: "my-app", expected: "my-app", description: "Name with hyphen" }, // Chinese characters { input: "我的应用", expected: "我的应用", description: "Chinese name" }, { input: "我的 App", expected: "我的_app", description: "Mixed Chinese and English", }, // Special characters { input: "App@2024", expected: "app@2024", description: "Special character @ (preserved)", }, { input: "My/App", expected: "my_app", description: "Forward slash" }, { input: "My\\App", expected: "my_app", description: "Backslash" }, { input: "App:Name", expected: "app_name", description: "Colon" }, { input: "App*Name", expected: "app_name", description: "Asterisk" }, { input: "App?Name", expected: "app_name", description: "Question mark" }, { input: 'App"Name', expected: "app_name", description: "Double quote" }, { input: "App", expected: "app_name_", description: "Angle brackets", }, { input: "App|Name", expected: "app_name", description: "Pipe" }, // Edge cases { input: "APP", expected: "app", description: "All uppercase" }, { input: "a", expected: "a", description: "Single character" }, { input: "123", expected: "123", description: "Numbers only" }, { input: " App ", expected: "_app_", description: "Leading/trailing spaces (collapsed)", }, { input: "App...", expected: "app", description: "Trailing dots" }, // Long names { input: "A".repeat(300), expected: "a".repeat(255), description: "Very long name (should truncate to 255)", }, ]; let passed = 0; let failed = 0; console.log("\n🧪 Testing getSafeAppName()"); console.log("─".repeat(50)); tests.forEach((test, index) => { try { const result = getSafeAppName(test.input); assert.equal( result, test.expected, `Expected "${test.expected}", got "${result}"`, ); console.log(` ✓ Test ${index + 1}: ${test.description}`); passed++; } catch (error) { console.log(` ✗ Test ${index + 1}: ${test.description}`); console.log(` Input: "${test.input}"`); console.log(` Expected: "${test.expected}"`); console.log(` Error: ${error.message}`); failed++; } }); console.log("─".repeat(50)); console.log(`Results: ${passed} passed, ${failed} failed\n`); return failed === 0; } /** * Test suite for download error notification (browser environment simulation) */ export function testDownloadErrorNotification() { console.log("\n🧪 Testing showDownloadError() Logic"); console.log("─".repeat(50)); const tests = [ { name: "Chinese language detection", language: "zh-CN", filename: "test.pdf", expectedTitle: "下载错误", expectedBody: "下载失败: test.pdf", }, { name: "English language detection", language: "en-US", filename: "document.docx", expectedTitle: "Download Error", expectedBody: "Download failed: document.docx", }, { name: "Traditional Chinese", language: "zh-TW", filename: "file.zip", expectedTitle: "下载错误", expectedBody: "下载失败: file.zip", }, { name: "Hong Kong Chinese", language: "zh-HK", filename: "image.png", expectedTitle: "下载错误", expectedBody: "下载失败: image.png", }, { name: "Special characters in filename", language: "en-US", filename: "my file (1).pdf", expectedTitle: "Download Error", expectedBody: "Download failed: my file (1).pdf", }, ]; let passed = 0; let failed = 0; tests.forEach((test, index) => { try { // Simulate language detection const isChineseLanguage = (lang) => lang && (lang.startsWith("zh") || lang.includes("CN") || lang.includes("TW") || lang.includes("HK")); const isChinese = isChineseLanguage(test.language); const title = isChinese ? "下载错误" : "Download Error"; const body = isChinese ? `下载失败: ${test.filename}` : `Download failed: ${test.filename}`; assert.equal( title, test.expectedTitle, `Title mismatch for ${test.name}`, ); assert.equal(body, test.expectedBody, `Body mismatch for ${test.name}`); console.log(` ✓ Test ${index + 1}: ${test.name}`); console.log(` Language: ${test.language}`); console.log(` Title: "${title}"`); console.log(` Body: "${body}"`); passed++; } catch (error) { console.log(` ✗ Test ${index + 1}: ${test.name}`); console.log(` Error: ${error.message}`); failed++; } }); console.log("─".repeat(50)); console.log(`Results: ${passed} passed, ${failed} failed\n`); return failed === 0; } /** * Run all tests */ export async function runHelperTests() { console.log("\n📦 Helper Functions Unit Tests"); console.log("=".repeat(50)); const results = []; // Test getSafeAppName results.push({ name: "getSafeAppName()", passed: testGetSafeAppName(), }); // Test download error notification results.push({ name: "showDownloadError() Logic", passed: testDownloadErrorNotification(), }); // Summary const allPassed = results.every((r) => r.passed); const passedCount = results.filter((r) => r.passed).length; const totalCount = results.length; console.log("\n📊 Helper Tests Summary"); console.log("=".repeat(50)); results.forEach((result) => { const icon = result.passed ? "✅" : "❌"; console.log(`${icon} ${result.name}`); }); console.log("=".repeat(50)); console.log(`Total: ${passedCount}/${totalCount} test suites passed\n`); return allPassed; } // Run tests if executed directly if (import.meta.url === `file://${process.argv[1]}`) { runHelperTests() .then((success) => { process.exit(success ? 0 : 1); }) .catch((error) => { console.error("Test execution failed:", error); process.exit(1); }); }