import { expect, tap } from '@git.zone/tstest/tapbundle'; import * as smartupdate from '../ts/index.js'; let testSmartUpdate: smartupdate.SmartUpdate; let silentSmartUpdate: smartupdate.SmartUpdate; // Test suite for backward compatibility tap.test('backward compatibility: should create an instance of SmartUpdate', async () => { testSmartUpdate = new smartupdate.SmartUpdate(); expect(testSmartUpdate).toBeInstanceOf(smartupdate.SmartUpdate); }); tap.test('backward compatibility: should check for a npm module using old API', async () => { const result = await testSmartUpdate.check('lodash', '1.0.5'); expect(result).toBeTrue(); }); // Test suite for new modern API tap.test('modern API: should create SmartUpdate with custom options', async () => { silentSmartUpdate = new smartupdate.SmartUpdate({ logLevel: 'SILENT', noColor: true, cacheDuration: { minutes: 30 }, }); expect(silentSmartUpdate).toBeInstanceOf(smartupdate.SmartUpdate); }); tap.test('modern API: checkForUpdate should return rich result object', async () => { const result = await silentSmartUpdate.checkForUpdate({ packageName: 'lodash', currentVersion: '1.0.0', cacheStrategy: 'never', }); // Verify result structure expect(result).toBeTypeOf('object'); expect(result.status).toBeTypeOf('string'); expect(result.packageName).toEqual('lodash'); expect(result.currentVersion).toEqual('1.0.0'); expect(result.checkTime).toBeInstanceOf(Date); expect(result.cacheHit).toBeTypeOf('boolean'); // Should have update available (1.0.0 is old) expect(result.status).toEqual('update-available'); expect(result.latestVersion).toBeTypeOf('string'); }); tap.test('modern API: checkForUpdate with up-to-date version', async () => { const result = await silentSmartUpdate.checkForUpdate({ packageName: '@push.rocks/smartversion', currentVersion: '999.999.999', // Future version cacheStrategy: 'never', }); expect(result.status).toEqual('up-to-date'); expect(result.latestVersion).toBeTypeOf('string'); }); tap.test('modern API: getLatestVersion utility method', async () => { const latestVersion = await silentSmartUpdate.getLatestVersion('lodash'); expect(latestVersion).toBeTypeOf('string'); expect(latestVersion).toMatch(/^\d+\.\d+\.\d+/); // Semver format }); tap.test('modern API: error handling for non-existent package', async () => { const result = await silentSmartUpdate.checkForUpdate({ packageName: 'this-package-definitely-does-not-exist-12345', currentVersion: '1.0.0', cacheStrategy: 'never', }); expect(result.status).toEqual('error'); expect(result.error).toBeInstanceOf(Error); }); tap.test('modern API: cache strategy works', async () => { // Clear cache first to ensure clean state const testPackage = 'express'; try { await silentSmartUpdate.clearCache(testPackage); } catch (e) { // Cache might not exist, that's fine } // First check - should hit registry with 'never' strategy const result1 = await silentSmartUpdate.checkForUpdate({ packageName: testPackage, currentVersion: '1.0.0', cacheStrategy: 'never', }); expect(result1.cacheHit).toBeFalse(); expect(result1.status).toEqual('update-available'); // Do a second check with time-based that will create cache const result2 = await silentSmartUpdate.checkForUpdate({ packageName: testPackage, currentVersion: '1.0.0', cacheStrategy: 'time-based', }); // Third immediate check - should use cache with 'always' strategy const result3 = await silentSmartUpdate.checkForUpdate({ packageName: testPackage, currentVersion: '1.0.0', cacheStrategy: 'always', }); expect(result3.cacheHit).toBeTrue(); expect(result3.status).toEqual('check-skipped'); // nextCheckTime may or may not be set depending on cache strategy implementation if (result3.nextCheckTime) { expect(result3.nextCheckTime).toBeInstanceOf(Date); } }); tap.test('modern API: exports all types and classes', async () => { // Verify exports expect(smartupdate.SmartUpdate).toBeTypeOf('function'); expect(smartupdate.UpdateCacheManager).toBeTypeOf('function'); expect(smartupdate.UpdateNotifier).toBeTypeOf('function'); expect(smartupdate.RegistryUnavailableError).toBeTypeOf('function'); expect(smartupdate.PackageNotFoundError).toBeTypeOf('function'); expect(smartupdate.LOG_LEVELS).toBeTypeOf('object'); }); export default tap.start();