onix-parser
Version:
Parse ONIX 3.0 XML files and extract structured product data for publishing and digital books
260 lines (212 loc) โข 7.35 kB
JavaScript
const fs = require('fs')
const path = require('path')
const onix = require('./onix')
/**
* Enhanced test suite for ONIX parser
*/
class OnixTester {
constructor() {
this.results = {
passed: 0,
failed: 0,
total: 0,
errors: []
}
this.outputDir = './test-results'
this.ensureOutputDir()
}
ensureOutputDir() {
if (!fs.existsSync(this.outputDir)) {
fs.mkdirSync(this.outputDir, { recursive: true })
}
}
async runAllTests() {
console.log('๐ Starting ONIX Parser Test Suite')
console.log('='.repeat(50))
// Test individual files
await this.testIndividualFiles()
// Test edge cases
await this.testEdgeCases()
// Test performance
await this.testPerformance()
this.printSummary()
}
async testIndividualFiles() {
console.log('\n๐ Testing Individual ONIX Files')
console.log('-'.repeat(30))
const testFiles = this.getTestFiles()
for (const file of testFiles) {
await this.testSingleFile(file)
}
}
async testSingleFile(filename) {
const filePath = `./files/${filename}`
const testName = filename.replace('.xml', '')
try {
console.log(`Testing ${filename}...`)
const startTime = Date.now()
const result = await onix(filePath)
const duration = Date.now() - startTime
if (result.status) {
console.log(` โ
${testName} - Parsed successfully (${duration}ms)`)
console.log(` Title: ${result.data.title?.titleText || 'N/A'}`)
console.log(` ISBN: ${result.data.iSNB13 || 'N/A'}`)
console.log(` Format: ${result.data.productFormDetail?.detail || 'N/A'}`)
console.log(` Price: ${result.data.priceBRL || 'N/A'} BRL`)
// Save successful results
const outputFile = path.join(this.outputDir, `${testName}.json`)
fs.writeFileSync(outputFile, JSON.stringify(result, null, 2))
this.results.passed++
} else {
console.log(` โ ${testName} - Failed`)
console.log(` Errors: ${result.message.join(', ')}`)
// Save failed results for analysis
const errorFile = path.join(this.outputDir, `${testName}-error.json`)
fs.writeFileSync(errorFile, JSON.stringify(result, null, 2))
this.results.failed++
this.results.errors.push({ file: filename, errors: result.message })
}
this.results.total++
} catch (error) {
console.log(` ๐ฅ ${testName} - Exception: ${error.message}`)
this.results.failed++
this.results.total++
this.results.errors.push({ file: filename, errors: [error.message] })
}
}
async testEdgeCases() {
console.log('\n๐งช Testing Edge Cases')
console.log('-'.repeat(20))
const edgeCases = [
{
name: 'Non-existent file',
test: () => onix('./files/non-existent.xml')
},
{
name: 'Invalid file path',
test: () => onix(null)
},
{
name: 'Empty string path',
test: () => onix('')
},
{
name: 'Invalid path type',
test: () => onix(123)
}
]
for (const testCase of edgeCases) {
try {
console.log(`Testing ${testCase.name}...`)
const result = await testCase.test()
if (!result.status) {
console.log(` โ
${testCase.name} - Correctly handled with error: ${result.message[0]}`)
} else {
console.log(` โ ${testCase.name} - Should have failed but didn't`)
}
} catch (error) {
console.log(` โ
${testCase.name} - Correctly threw exception: ${error.message}`)
}
}
}
async testPerformance() {
console.log('\nโก Performance Tests')
console.log('-'.repeat(18))
const testFiles = this.getTestFiles().slice(0, 5) // Test with first 5 files
const times = []
for (const file of testFiles) {
const filePath = `./files/${file}`
if (!fs.existsSync(filePath)) continue
const startTime = Date.now()
await onix(filePath)
const duration = Date.now() - startTime
times.push(duration)
console.log(` ๐ ${file}: ${duration}ms`)
}
if (times.length > 0) {
const avgTime = times.reduce((a, b) => a + b, 0) / times.length
const maxTime = Math.max(...times)
const minTime = Math.min(...times)
console.log(`\n Average: ${avgTime.toFixed(1)}ms`)
console.log(` Min: ${minTime}ms, Max: ${maxTime}ms`)
}
}
getTestFiles() {
const filesDir = './files'
if (!fs.existsSync(filesDir)) {
console.log('โ ๏ธ Files directory not found')
return []
}
return fs.readdirSync(filesDir)
.filter(file => file.endsWith('.xml'))
.sort()
}
printSummary() {
console.log('\n' + '='.repeat(50))
console.log('๐ TEST SUMMARY')
console.log('='.repeat(50))
console.log(`Total tests: ${this.results.total}`)
console.log(`Passed: ${this.results.passed} โ
`)
console.log(`Failed: ${this.results.failed} โ`)
if (this.results.total > 0) {
const successRate = ((this.results.passed / this.results.total) * 100).toFixed(1)
console.log(`Success rate: ${successRate}%`)
}
if (this.results.errors.length > 0) {
console.log('\nโ FAILED TESTS:')
this.results.errors.forEach(error => {
console.log(` ${error.file}: ${error.errors.join(', ')}`)
})
}
console.log(`\n๐ Results saved to: ${this.outputDir}`)
console.log('='.repeat(50))
}
// Generate a test report
generateReport() {
const report = {
timestamp: new Date().toISOString(),
summary: this.results,
details: {
totalFiles: this.getTestFiles().length,
outputDirectory: this.outputDir
}
}
const reportFile = path.join(this.outputDir, 'test-report.json')
fs.writeFileSync(reportFile, JSON.stringify(report, null, 2))
console.log(`๐ Detailed report saved to: ${reportFile}`)
}
}
// Quick test function for individual files
async function quickTest(filename) {
console.log(`๐ Quick test for ${filename}`)
const result = await onix(`./files/${filename}`)
if (result.status) {
console.log('โ
Success!')
console.log('๐ Title:', result.data.title?.titleText)
console.log('๐ ISBN:', result.data.iSNB13)
console.log('๐ฐ Price:', result.data.priceBRL, 'BRL')
} else {
console.log('โ Failed:', result.message.join(', '))
}
return result
}
// Run tests based on command line arguments or run all
async function main() {
const args = process.argv.slice(2)
if (args.length > 0) {
// Test specific file
const filename = args[0].endsWith('.xml') ? args[0] : `${args[0]}.xml`
await quickTest(filename)
} else {
// Run full test suite
const tester = new OnixTester()
await tester.runAllTests()
tester.generateReport()
}
}
// Export for use in other files
module.exports = { OnixTester, quickTest }
// Run if called directly
if (require.main === module) {
main().catch(console.error)
}