Skip to content

test: add log reader test suite with file existence and content valid… #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
74 changes: 74 additions & 0 deletions src/test/logReader.test.ts
Original file line number Diff line number Diff line change
@@ -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');
});
});
81 changes: 81 additions & 0 deletions src/test/reportReader.test.ts
Original file line number Diff line number Diff line change
@@ -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
});