js-partial-classes
Version:
A utility package for supplementing main classes with methods from partial classes, supporting both static and instance methods.
218 lines (168 loc) • 6.34 kB
JavaScript
import { supplement } from '../index.js';
/**
* Test suite for the supplement function
*/
class SupplementTestSuite {
constructor() {
this.testCount = 0;
this.passedTests = 0;
this.failedTests = 0;
}
// Test helper methods
assert(condition, message) {
this.testCount++;
if (condition) {
this.passedTests++;
console.log(`✅ ${message}`);
} else {
this.failedTests++;
console.log(`❌ ${message}`);
}
}
assertEqual(actual, expected, message) {
this.testCount++;
if (actual === expected) {
this.passedTests++;
console.log(`✅ ${message}`);
} else {
this.failedTests++;
console.log(`❌ ${message}: expected ${expected}, got ${actual}`);
}
}
// Test classes
createMainClass() {
return class MainClass {
constructor() {
this.name = 'Main';
}
mainMethod() {
return 'Main method';
}
};
}
createPartialClass() {
return class PartialClass {
static staticMethod() {
return 'Static method from partial';
}
instanceMethod() {
return 'Instance method from partial';
}
anotherInstanceMethod() {
return 'Another instance method';
}
};
}
// Test cases
async testDirectClassReference() {
console.log('\n🧪 Testing direct class reference...');
const MainClass = this.createMainClass();
const PartialClass = this.createPartialClass();
await supplement(MainClass, PartialClass);
const instance = new MainClass();
this.assertEqual(instance.mainMethod(), 'Main method', 'Main method should remain unchanged');
this.assertEqual(MainClass.staticMethod(), 'Static method from partial', 'Static method should be supplemented');
this.assertEqual(instance.instanceMethod(), 'Instance method from partial', 'Instance method should be supplemented');
this.assertEqual(instance.anotherInstanceMethod(), 'Another instance method', 'Another instance method should be supplemented');
}
async testStringPathImport() {
console.log('\n🧪 Testing string path import...');
const MainClass = this.createMainClass();
await supplement(MainClass, './test-partial.js');
const instance = new MainClass();
this.assertEqual(instance.mainMethod(), 'Main method', 'Main method should remain unchanged');
this.assertEqual(MainClass.staticMethod(), 'Static method from partial', 'Static method should be supplemented');
this.assertEqual(instance.instanceMethod(), 'Instance method from partial', 'Instance method should be supplemented');
}
async testPromiseImport() {
console.log('\n🧪 Testing promise import...');
const MainClass = this.createMainClass();
await supplement(MainClass, import('./test-partial.js'));
const instance = new MainClass();
this.assertEqual(instance.mainMethod(), 'Main method', 'Main method should remain unchanged');
this.assertEqual(MainClass.staticMethod(), 'Static method from partial', 'Static method should be supplemented');
this.assertEqual(instance.instanceMethod(), 'Instance method from partial', 'Instance method should be supplemented');
}
async testMethodOverride() {
console.log('\n🧪 Testing method override...');
const MainClass = class {
static staticMethod() {
return 'Original static method';
}
instanceMethod() {
return 'Original instance method';
}
};
const PartialClass = class {
static staticMethod() {
return 'Overridden static method';
}
instanceMethod() {
return 'Overridden instance method';
}
};
await supplement(MainClass, PartialClass);
const instance = new MainClass();
this.assertEqual(MainClass.staticMethod(), 'Overridden static method', 'Static method should be overridden');
this.assertEqual(instance.instanceMethod(), 'Overridden instance method', 'Instance method should be overridden');
}
async testConstructorExclusion() {
console.log('\n🧪 Testing constructor exclusion...');
const MainClass = class {
constructor() {
this.mainConstructor = true;
}
};
const PartialClass = class {
constructor() {
this.partialConstructor = true;
}
};
await supplement(MainClass, PartialClass);
const instance = new MainClass();
this.assert(instance.mainConstructor, 'Main constructor should be preserved');
this.assert(!instance.partialConstructor, 'Partial constructor should not be copied');
}
async testNonWritableProperties() {
console.log('\n🧪 Testing non-writable properties...');
const MainClass = class {};
const PartialClass = class {
static get readOnlyProperty() {
return 'readonly';
}
};
// Define a non-writable property
Object.defineProperty(PartialClass, 'nonWritable', {
value: 'non-writable',
writable: false
});
await supplement(MainClass, PartialClass);
this.assert(!MainClass.hasOwnProperty('readOnlyProperty'), 'Read-only properties should not be copied');
this.assert(!MainClass.hasOwnProperty('nonWritable'), 'Non-writable properties should not be copied');
}
async runAllTests() {
console.log('🚀 Starting supplement function tests...\n');
try {
await this.testDirectClassReference();
await this.testStringPathImport();
await this.testPromiseImport();
await this.testMethodOverride();
await this.testConstructorExclusion();
await this.testNonWritableProperties();
console.log(`\n📊 Test Results:`);
console.log(` Total tests: ${this.testCount}`);
console.log(` Passed: ${this.passedTests}`);
console.log(` Failed: ${this.failedTests}`);
if (this.failedTests === 0) {
console.log('\n🎉 All supplement tests passed!');
} else {
console.log('\n❌ Some supplement tests failed!');
}
} catch (error) {
console.error('❌ Test suite error:', error);
}
}
}
// Run the test suite
const testSuite = new SupplementTestSuite();
testSuite.runAllTests();