nrel-spa/test-cjs.cjs
Aric Camarata b44d9a958b v2.0.0: TypeScript rewrite with dual CJS/ESM build
Complete modernization of the package. The core SPA algorithm is
unchanged and validated; everything else is rebuilt to match current
JavaScript ecosystem standards.

Changes:
- TypeScript wrapper in src/ with full type definitions
- Dual CJS/ESM build via tsup (dist/index.cjs, dist/index.mjs)
- Core algorithm moved from dist/spa.js to lib/spa.js (same code)
- Input validation with descriptive TypeError/RangeError messages
- formatTime() and SPA function code constants as named exports
- getSpa() / calcSpa() accept null for optional args (tz, options)
- Test suite: 61 ESM assertions and 17 CJS assertions
- GitHub Actions CI: Node 20/22/24 matrix, typecheck, pack-check
- GitHub Wiki: Home, API Reference, Architecture, Twilight, NREL SPA
- NREL attribution in LICENSE and README per their license terms
- package.json: exports map, files, engines >=20, sideEffects: false
- Author corrected to Aric Camarata; repository.url uses git+https://
- LICENSE year corrected to 2023-2026
- Removed: index.js, test.js, dist/spa.js (superseded by above)
2026-02-25 11:01:38 -05:00

76 lines
3.3 KiB
JavaScript

'use strict';
const assert = require('node:assert/strict');
const {
getSpa,
calcSpa,
formatTime,
SPA_ZA,
SPA_ZA_RTS,
SPA_ALL,
} = require('./dist/index.cjs');
let passed = 0;
let failed = 0;
function test(name, fn) {
try {
fn();
console.log(`${name}... PASS`);
passed++;
} catch (err) {
console.error(`${name}... FAIL: ${err.message}`);
failed++;
}
}
// ─── Exports ─────────────────────────────────────────────────────────────────
test('CJS: getSpa is a function', () => assert.equal(typeof getSpa, 'function'));
test('CJS: calcSpa is a function', () => assert.equal(typeof calcSpa, 'function'));
test('CJS: formatTime is a function', () => assert.equal(typeof formatTime, 'function'));
test('CJS: SPA_ZA === 0', () => assert.equal(SPA_ZA, 0));
test('CJS: SPA_ZA_RTS === 2', () => assert.equal(SPA_ZA_RTS, 2));
test('CJS: SPA_ALL === 3', () => assert.equal(SPA_ALL, 3));
// ─── Correctness ──────────────────────────────────────────────────────────────
const nyc = calcSpa(
new Date('2025-06-21T00:00:00Z'),
40.7128, -74.006, -4,
{ elevation: 10, pressure: 1013, temperature: 20 },
);
test('CJS: NYC sunrise = 05:25:03', () => assert.equal(nyc.sunrise, '05:25:03'));
test('CJS: NYC solarNoon = 12:57:56', () => assert.equal(nyc.solarNoon, '12:57:56'));
test('CJS: NYC sunset = 20:30:35', () => assert.equal(nyc.sunset, '20:30:35'));
test('CJS: zenith is number', () => assert.equal(typeof nyc.zenith, 'number'));
test('CJS: azimuth 0-360', () => assert.ok(nyc.azimuth >= 0 && nyc.azimuth <= 360));
// ─── formatTime ───────────────────────────────────────────────────────────────
test('CJS formatTime: noon', () => assert.equal(formatTime(12), '12:00:00'));
test('CJS formatTime: negative = N/A', () => assert.equal(formatTime(-1), 'N/A'));
test('CJS formatTime: NaN = N/A', () => assert.equal(formatTime(NaN), 'N/A'));
// ─── Custom angles ────────────────────────────────────────────────────────────
const twilight = getSpa(
new Date('2025-06-21T00:00:00Z'),
40.7128, -74.006, -4,
{ elevation: 10 },
[96, 102, 108],
);
test('CJS angles: has angles array', () => assert.ok(Array.isArray(twilight.angles)));
test('CJS angles: three entries', () => assert.equal(twilight.angles.length, 3));
test('CJS angles: civil < standard sunrise', () => {
const standard = getSpa(new Date('2025-06-21T00:00:00Z'), 40.7128, -74.006, -4, { elevation: 10 });
assert.ok(twilight.angles[0].sunrise < standard.sunrise);
});
// ─── Summary ─────────────────────────────────────────────────────────────────
console.log('---');
console.log(`${passed + failed} tests total: ${passed} passed, ${failed} failed`);
if (failed > 0) process.exit(1);