diff --git a/CHANGELOG.md b/CHANGELOG.md index 883dd7b..c86917b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,8 @@ All notable changes to the "magento-log-viewer" extension will be documented in - fix: Improved badge updates with throttling and debouncing: Prevents too frequent updates and implements more efficient counting methods. - fix: improve type safety in report handling functions - i18n: translations added - +- test: add log reader test suite with file existence and content validation +- test: add report reader test suite with file existence and content validation --- ## Latest Release diff --git a/src/test/logReader.test.ts b/src/test/logReader.test.ts new file mode 100644 index 0000000..bcce38b --- /dev/null +++ b/src/test/logReader.test.ts @@ -0,0 +1,74 @@ +import * as assert from 'assert'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as os from 'os'; + +// Import the main module components to test +import { LogViewerProvider, LogItem } from '../logViewer'; + +suite('Log Reader Test Suite', () => { + // Create a temporary directory for test logs + const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'magento-logviewer-test-')); + const logFilePath = path.join(tempDir, 'test.log'); + + // Sample log content with different log levels + const sampleLogContent = `[2025-05-28T21:13:28.751586+00:00] .Info: Broken reference: the 'amcompany_toolbar_link' element cannot be added as child to 'header.links', because the latter doesn't exist +[2025-05-28T21:13:28.751586+00:00] .Warn: Broken reference: the 'amcompany_toolbar_link' element cannot be added as child to 'header.links', because the latter doesn't exist +[2025-05-28T21:13:29.123456+00:00] .Debug: Debug message: initializing module +[2025-05-28T21:13:30.234567+00:00] .Error: Failed to load resource: server responded with status 404 +[2025-05-28T21:13:31.345678+00:00] .Critical: Database connection failed`; + + // Set up and tear down + suiteSetup(() => { + // Create the test log file before tests + fs.writeFileSync(logFilePath, sampleLogContent); + }); + + suiteTeardown(() => { + // Clean up test files after tests + try { + fs.unlinkSync(logFilePath); + fs.rmdirSync(tempDir); + } catch (err) { + console.error('Failed to clean up test files:', err); + } + }); + + test('Log file should exist', () => { + assert.strictEqual(fs.existsSync(logFilePath), true, 'Test log file should exist'); + }); + + test('Log file should be readable', () => { + const content = fs.readFileSync(logFilePath, 'utf-8'); + assert.strictEqual(content, sampleLogContent, 'Log file content should match the sample content'); + }); + + test('LogViewerProvider should read log file correctly', async () => { + // Create a LogViewerProvider instance with the temp directory as root + const logProvider = new LogViewerProvider(tempDir); // Get access to private method (this requires modifying the class or using a type assertion) + // For this test, we'll use a type assertion to access the private method + + // Use a specific interface that defines the method we need for testing + interface LogViewerInternals { + getLogFileLines(filePath: string): LogItem[]; + } + + // Cast to our specific interface instead of 'any' + const provider = logProvider as unknown as LogViewerInternals; + const logItems = provider.getLogFileLines(logFilePath); + + // Get all log levels from the items + const logLevels = logItems.map((item: LogItem) => item.label?.toString().split(' ')[0]); + console.log('Found log levels:', logLevels); + + // Verify log file is parsed correctly and contains expected entries + assert.ok(logItems.length > 0, 'Should parse log entries'); + + // Find if any log level contains Info, Warn, etc (case-insensitive) + assert.ok(logLevels.some((level: unknown) => typeof level === 'string' && level.includes('INFO')), 'Should contain INFO level logs'); + assert.ok(logLevels.some((level: unknown) => typeof level === 'string' && level.includes('WARN')), 'Should contain WARN level logs'); + assert.ok(logLevels.some((level: unknown) => typeof level === 'string' && level.includes('DEBUG')), 'Should contain DEBUG level logs'); + assert.ok(logLevels.some((level: unknown) => typeof level === 'string' && level.includes('ERROR')), 'Should contain ERROR level logs'); + assert.ok(logLevels.some((level: unknown) => typeof level === 'string' && level.includes('CRITICAL')), 'Should contain CRITICAL level logs'); + }); +}); diff --git a/src/test/reportReader.test.ts b/src/test/reportReader.test.ts new file mode 100644 index 0000000..945426b --- /dev/null +++ b/src/test/reportReader.test.ts @@ -0,0 +1,81 @@ +import * as assert from 'assert'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as os from 'os'; + +// Import the main module components to test +import { ReportViewerProvider, LogItem } from '../logViewer'; + +suite('Report Reader Test Suite', () => { + // Create a temporary directory for test reports + const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'magento-reportviewer-test-')); + const reportFilePath = path.join(tempDir, 'report.json'); + + // Sample report content (Magento error report format) + const sampleReportContent = JSON.stringify({ + "0": "Error", + "1": "Exception: Broken reference: the 'amcompany_toolbar_link' element cannot be added as child to 'header.links', because the latter doesn't exist", + "2": "#1 Magento\\Framework\\View\\Layout\\Generator\\Structure->scheduleStructure() called at /var/www/html/vendor/magento/framework/View/Layout/GeneratorPool.php:105", + "3": "#2 Magento\\Framework\\View\\Layout\\GeneratorPool->process() called at /var/www/html/vendor/magento/framework/View/Layout.php:352", + "url": "/customer/account/login/", + "script_name": "/index.php", + "report_id": "12345abcde" + }, null, 2); + + // Set up and tear down + suiteSetup(() => { + // Create the test report file before tests + fs.writeFileSync(reportFilePath, sampleReportContent); + }); + + suiteTeardown(() => { + // Clean up test files after tests + try { + fs.unlinkSync(reportFilePath); + fs.rmdirSync(tempDir); + } catch (err) { + console.error('Failed to clean up test files:', err); + } + }); + + test('Report file should exist', () => { + assert.strictEqual(fs.existsSync(reportFilePath), true, 'Test report file should exist'); + }); + + test('Report file should be readable', () => { + const content = fs.readFileSync(reportFilePath, 'utf-8'); + assert.strictEqual(content, sampleReportContent, 'Report file content should match the sample content'); + }); + + test('ReportViewerProvider should read report file correctly', async () => { + // Create a ReportViewerProvider instance with the temp directory as root + const reportProvider = new ReportViewerProvider(tempDir); + + // Interface for accessing private methods for testing + interface ReportViewerInternals { + getLogItems(dir: string, label: string): LogItem[]; + } + + // Access the provider's internal methods + const provider = reportProvider as unknown as ReportViewerInternals; + + // Get report items from the directory + const reportItems = provider.getLogItems(tempDir, 'Reports'); + + // Basic validation that reports were found + assert.ok(reportItems.length > 0, 'Should find report entries'); + + // Verify report content is correctly parsed + const reportItem = reportItems[0]; + assert.ok(reportItem.label?.toString().includes('Error'), 'Report label should include the error type from the report'); + + // Also check if the command arguments contain the file path + assert.ok(reportItem.command && + reportItem.command.arguments && + reportItem.command.arguments[0] && + reportItem.command.arguments[0].endsWith('report.json'), + 'Report item should have command with file path'); + }); + + // Additional test for report content parsing if needed +});