fix(weather): preserve enable during first-load replacement

This commit is contained in:
Said committed 2026-10-20 00:55:40 +01:00
1 parent de2138e84c
commit 0cb6857229
5 files changed
+80 -7

No files matched your search

+11 -4
View File
@@ -357,7 +357,7 @@ export function createWeatherLayer({
signal: controller.signal,
});
if (!enabled || controller.signal.aborted || request !== controller)
return false;
return enabled && !signal?.aborted && request !== controller;
if (snapshot.unavailable) {
error = msg(
'Weather source unavailable; previous observation retained',
@@ -376,7 +376,9 @@ export function createWeatherLayer({
)
await show(snapshot.latest, controller.signal);
return (
!controller.signal.aborted && request === controller && enabled
enabled &&
!signal?.aborted &&
(!controller.signal.aborted || request !== controller)
);
}
const time =
@@ -388,9 +390,14 @@ export function createWeatherLayer({
(satellite && rendering.getDiagnostics().infrared !== infrared)
)
await show(time, controller.signal);
return !controller.signal.aborted && request === controller && enabled;
return (
enabled &&
!signal?.aborted &&
(!controller.signal.aborted || request !== controller)
);
} catch (cause) {
if (controller.signal.aborted || request !== controller) return false;
if (controller.signal.aborted || request !== controller)
return enabled && !signal?.aborted && request !== controller;
error = cause?.message || msg('Weather unavailable');
stop();
return true;
+31 -1
View File
@@ -694,7 +694,11 @@ test('superseding a pending stage preserves the newer manifest loading state', a
await flush();
const newer = h.layer.update();
await flush();
assert.equal(await old, false);
assert.equal(
await old,
true,
'replacement is accepted by the enable lifecycle',
);
assert.equal(
h.layer.getStats().loading,
true,
@@ -2311,3 +2315,29 @@ for (const product of ['radar', 'clouds-regional', 'lightning']) {
assert.equal(h.viewer.camera.moveEnd.size, 0);
});
}
test('a product replacement accepts supersession but never paints the obsolete first response', async () => {
const pending = [];
const h = layerHarness({
id: 'weather-satellite',
feed: {
getSnapshot: (args) => {
const task = deferred();
pending.push({ ...args, ...task });
return task.promise;
},
},
});
const first = h.layer.update();
h.layer.setParams({ product: 'clouds' });
assert.equal(pending.length, 2);
pending[0].resolve({ ...snapshot, product: 'clouds-regional' });
assert.equal(await first, true);
assert.equal(h.stages.length, 0);
pending[1].resolve({ ...snapshot, product: 'clouds' });
await flush();
h.stages.at(-1).finish();
await flush();
assert.equal(h.layer.getParams().product, 'clouds');
h.layer.destroy();
});
+3 -2
View File
@@ -180,7 +180,7 @@ export function createWindLayer({
overlay: requestedScalar(),
});
if (!enabled || controller.signal.aborted || request !== controller)
return false;
return enabled && !signal?.aborted && request !== controller;
manifest = snapshot;
error = null;
if (sampledPosition) sample(sampledPosition);
@@ -194,7 +194,8 @@ export function createWindLayer({
}
return true;
} catch (cause) {
if (controller.signal.aborted || request !== controller) return false;
if (controller.signal.aborted || request !== controller)
return enabled && !signal?.aborted && request !== controller;
error = cause?.message || msg('Wind source unavailable');
return true;
} finally {
+33
View File
@@ -412,3 +412,36 @@ test('wind unit chips appear only alongside a speed legend, including canvas tra
for (const overlay of ['pressure', 'temperature', 'none']) { layer.setParams({ overlay }); assert.deepEqual(unitChips(), []); }
layer.destroy();
});
test('a parameter replacement during manager enable does not roll the layer back', async () => {
const { LayerLifecycle } = await import('../../data/lifecycle.js');
const pending = [];
const rendering = Object.fromEntries(
['attach', 'start', 'stop', 'clear', 'destroy', 'setField'].map((name) => [
name,
() => {},
]),
);
const layer = createWindLayer({
feed: {
getSnapshot: (args) =>
new Promise((resolve) => pending.push({ ...args, resolve })),
},
createRendering: () => rendering,
});
const manager = new LayerLifecycle({ container: {} });
manager.register(layer);
const enabled = manager.setEnabled('wind', true);
for (let i = 0; i < 20 && !pending.length; i++) await Promise.resolve();
layer.setParams({ model: 'ifs' });
await Promise.resolve();
pending[0].resolve(snapshot('gfs'));
assert.equal(await enabled, true);
assert.equal(manager.isEnabled('wind'), true);
assert.equal(layer.getStats().loading, true);
pending[1].resolve(snapshot('ifs'));
for (let i = 0; i < 10; i++) await Promise.resolve();
assert.equal(layer.getStats().model, 'IFS');
assert.equal(layer.getStats().count, 4);
await manager.destroyAll();
});