From 0ba4ae788d57f0e0805780bc90bde508a9d70a18 Mon Sep 17 00:00:00 2001 From: djabhi31 Date: Wed, 14 Oct 2026 23:01:38 +0530 Subject: [PATCH 1/2] test(launches): add finiteCoordinate and stage normalization edge-case coverage - Pin finiteCoordinate helper behavior across numeric, non-finite, and string inputs - Verify recovery stage downrange distance, flight numbers, and coordinates fall back safely to null on non-finite data - Pin recovery status transitions for LOST and EXPENDABLE stage categories - Verify payload massKg and amount normalization edge cases for blank, negative, and non-numeric values --- src/data/rocketLaunches.test.mjs | 138 +++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/src/data/rocketLaunches.test.mjs b/src/data/rocketLaunches.test.mjs index a1a3fab44..5ad1d732f 100644 --- a/src/data/rocketLaunches.test.mjs +++ b/src/data/rocketLaunches.test.mjs @@ -2,6 +2,7 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import * as Cesium from 'cesium'; import { gstime } from 'satellite.js'; +import { createModel } from '../layers/launches/model.js'; import rocketLaunchesLayer, { _setRocketMissionOverlayHostForTest, _setSelectedRocketMissionForTest, @@ -728,6 +729,143 @@ test('normalizes detailed payload and stage recovery records', () => { assert.equal(launches[0].recoveryStages[0].lon, -76.2); }); +test('finiteCoordinate normalizes finite numbers and rejects non-numeric or non-finite inputs', () => { + const model = createModel({}); + assert.equal(model.finiteCoordinate(42.5), 42.5); + assert.equal(model.finiteCoordinate('28.5619'), 28.5619); + assert.equal(model.finiteCoordinate('-80.5772'), -80.5772); + assert.equal(model.finiteCoordinate(0), 0); + assert.equal(model.finiteCoordinate('0'), 0); + assert.equal(model.finiteCoordinate(undefined), null); + assert.equal(model.finiteCoordinate('invalid'), null); + assert.equal(model.finiteCoordinate('TBD'), null); + assert.equal(model.finiteCoordinate(Number.NaN), null); + assert.equal(model.finiteCoordinate(Number.POSITIVE_INFINITY), null); + assert.equal(model.finiteCoordinate(Number.NEGATIVE_INFINITY), null); +}); + +test('normalizes recovery stage coordinates, downrange distance, and flight numbers with non-finite fallbacks', () => { + const launches = normalizeRocketLaunches( + { + results: [ + { + id: 'recovery-fallbacks', + name: 'Falcon 9 | Edge Case Stage Normalization', + net: '2026-07-20T10:00:00Z', + pad: { latitude: '28.608', longitude: '-80.604' }, + rocket: { + launcher_stage: [ + { + id: 88, + type: { name: 'Booster' }, + launcher_flight_number: 'invalid-flight', + landing: { + attempt: true, + success: false, + downrange_distance: 'TBD', + landing_location: { + name: 'Ocean Impact', + latitude: 'N/A', + longitude: undefined, + }, + }, + }, + { + id: 89, + type: { name: 'Expended Stage' }, + landing: { + attempt: false, + type: { name: 'Expendable' }, + }, + }, + ], + }, + }, + ], + }, + NOW, + ); + + assert.equal(launches[0].recoveryStages.length, 2); + + const booster = launches[0].recoveryStages[0]; + assert.equal(booster.status, 'LOST'); + assert.equal(booster.success, false); + assert.equal(booster.attempted, true); + assert.equal(booster.flightNumber, null); + assert.equal(booster.downrangeKm, null); + assert.equal(booster.lat, null); + assert.equal(booster.lon, null); + + const expendable = launches[0].recoveryStages[1]; + assert.equal(expendable.status, 'EXPENDABLE'); + assert.equal(expendable.attempted, false); + assert.equal(expendable.success, null); +}); + +test('normalizes payload edge cases for missing, blank, or invalid mass and non-numeric amounts', () => { + const launches = normalizeRocketLaunches( + { + results: [ + { + id: 'payload-edge-cases', + name: 'Electron | Mixed Payloads', + net: '2026-07-20T10:00:00Z', + pad: { latitude: '-39.26', longitude: '177.86' }, + rocket: { + payloads: [ + { + id: 601, + amount: 'not-a-number', + payload: { + id: 11, + name: 'Empty Mass Payload', + mass: '', + }, + }, + { + id: 602, + amount: 3, + payload: { + id: 12, + name: 'Negative Mass Payload', + mass: -50, + }, + }, + { + id: 603, + payload: { + id: 13, + name: 'Non-Numeric Mass Payload', + mass: 'unknown', + }, + }, + { + id: 604, + payload: { + id: 14, + name: 'Valid Fractional Mass Payload', + mass: '12.75', + }, + }, + ], + }, + }, + ], + }, + NOW, + ); + + const payloads = launches[0].payloads; + assert.equal(payloads.length, 4); + assert.equal(payloads[0].amount, 1); + assert.equal(payloads[0].massKg, null); + assert.equal(payloads[1].amount, 3); + assert.equal(payloads[1].massKg, null); + assert.equal(payloads[2].massKg, null); + assert.equal(payloads[3].massKg, 12.75); +}); + test('keeps payload and recovery collections empty when LL2 does not disclose them', () => { const launches = normalizeRocketLaunches({ results: [{ id: 'undisclosed', From 393f42aed5f5737c1d534b14a9ee8d3784736c3e Mon Sep 17 00:00:00 2001 From: Sameh Khamis Date: Fri, 16 Oct 2026 15:25:46 -0700 Subject: [PATCH 2/2] Drop payload mass checks that existing tests already pin Blank, negative and non-numeric masses are covered by the existing missing-payload test; keep the amount fallback and the fractional string mass. --- src/data/rocketLaunches.test.mjs | 31 +++++++------------------------ 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/src/data/rocketLaunches.test.mjs b/src/data/rocketLaunches.test.mjs index 5ad1d732f..ccfd280e2 100644 --- a/src/data/rocketLaunches.test.mjs +++ b/src/data/rocketLaunches.test.mjs @@ -803,7 +803,7 @@ test('normalizes recovery stage coordinates, downrange distance, and flight numb assert.equal(expendable.success, null); }); -test('normalizes payload edge cases for missing, blank, or invalid mass and non-numeric amounts', () => { +test('normalizes payload amounts and fractional string masses', () => { const launches = normalizeRocketLaunches( { results: [ @@ -817,33 +817,17 @@ test('normalizes payload edge cases for missing, blank, or invalid mass and non- { id: 601, amount: 'not-a-number', - payload: { - id: 11, - name: 'Empty Mass Payload', - mass: '', - }, + payload: { id: 11, name: 'Unknown Amount Payload' }, }, { id: 602, amount: 3, - payload: { - id: 12, - name: 'Negative Mass Payload', - mass: -50, - }, + payload: { id: 12, name: 'Triple Payload' }, }, { id: 603, payload: { id: 13, - name: 'Non-Numeric Mass Payload', - mass: 'unknown', - }, - }, - { - id: 604, - payload: { - id: 14, name: 'Valid Fractional Mass Payload', mass: '12.75', }, @@ -856,14 +840,13 @@ test('normalizes payload edge cases for missing, blank, or invalid mass and non- NOW, ); + // Blank, negative and non-numeric masses are pinned by "missing payload + // details stay unknown without inventing mass or classification". const payloads = launches[0].payloads; - assert.equal(payloads.length, 4); + assert.equal(payloads.length, 3); assert.equal(payloads[0].amount, 1); - assert.equal(payloads[0].massKg, null); assert.equal(payloads[1].amount, 3); - assert.equal(payloads[1].massKg, null); - assert.equal(payloads[2].massKg, null); - assert.equal(payloads[3].massKg, 12.75); + assert.equal(payloads[2].massKg, 12.75); }); test('keeps payload and recovery collections empty when LL2 does not disclose them', () => {