test(settings): cover dialog problem boundaries (#614)

Issue: #614
User-Visible: no
This commit is contained in:
Claude
2026-09-23 16:10:09 +03:00
parent 86c765d99e
commit a2d6371545
2 changed files with 133 additions and 1 deletions
+132
View File
@@ -0,0 +1,132 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { generalProblems } from '../test-build/editors/general-form-state.js';
import { markerProblems } from '../test-build/editors/marker-form-state.js';
import { spaceDialogProblems } from '../test-build/editors/space-form-state.js';
import { GRID_CELL_CM_MAX, GRID_CELL_CM_MIN } from '../test-build/grid-scale.js';
const fields = (problems) => problems.map(({ field, message }) => [field, message]);
const generalDraft = (glowRadiusInput, northDegInput = '') => ({
glowRadiusInput,
northDegInput,
});
test('#614 generalProblems validates required glow text without reviving the typed value', () => {
const glowError = [['gs-glow-radius', 'gs.error_glow_radius']];
assert.deepEqual(fields(generalProblems(generalDraft(''))), glowError);
assert.deepEqual(fields(generalProblems(generalDraft(' '))), glowError);
assert.deepEqual(fields(generalProblems(generalDraft('glow'))), glowError);
assert.deepEqual(fields(generalProblems(generalDraft('0'))), glowError);
assert.deepEqual(fields(generalProblems(generalDraft('-0'))), glowError);
assert.deepEqual(fields(generalProblems(generalDraft('-1'))), glowError);
assert.deepEqual(fields(generalProblems(generalDraft('0,01'))), []);
assert.deepEqual(fields(generalProblems(generalDraft('25'))), []);
});
test('#614 generalProblems keeps north optional but enforces integer compass bounds', () => {
const northError = [['gs-north', 'gs.error_north']];
for (const raw of ['', ' ', '0', '359']) {
assert.deepEqual(fields(generalProblems(generalDraft('25', raw))), [], raw);
}
for (const raw of ['north', '12,5', '-1', '360']) {
assert.deepEqual(fields(generalProblems(generalDraft('25', raw))), northError, raw);
}
});
const baseSpace = (patch = {}) => ({
title: 'Ground floor',
cellCm: 5,
cellCmInput: '5',
source: 'draw',
planFile: null,
planUrl: null,
fillMode: 'none',
tempMin: 18,
tempMax: 26,
tempMinInput: '18',
tempMaxInput: '26',
northDeg: null,
northDegInput: '',
...patch,
});
const spaceFields = (patch = {}, imperial = false) =>
fields(spaceDialogProblems(baseSpace(patch), 'space', imperial));
test('#614 spaceDialogProblems validates raw scale text and persisted bounds', () => {
const scaleError = [['space-cell-cm', 'space.error_scale']];
for (const raw of ['', ' ', 'scale', '0', String(GRID_CELL_CM_MIN - 0.01), String(GRID_CELL_CM_MAX + 1)]) {
assert.deepEqual(spaceFields({ cellCmInput: raw }), scaleError, raw);
}
for (const raw of [String(GRID_CELL_CM_MIN), '1,5', String(GRID_CELL_CM_MAX)]) {
assert.deepEqual(spaceFields({ cellCmInput: raw }), [], raw);
}
});
test('#614 spaceDialogProblems reports each temperature input and then the range', () => {
assert.deepEqual(spaceFields({ fillMode: 'temp', tempMinInput: '', tempMaxInput: ' ' }), [
['space-temp-min', 'space.error_temp_value'],
['space-temp-max', 'space.error_temp_value'],
]);
assert.deepEqual(spaceFields({ fillMode: 'temp', tempMinInput: 'cold', tempMaxInput: '24' }), [
['space-temp-min', 'space.error_temp_value'],
]);
assert.deepEqual(spaceFields({ fillMode: 'temp', tempMinInput: '18,5', tempMaxInput: '24,5' }), []);
assert.deepEqual(spaceFields({ fillMode: 'temp', tempMinInput: '20', tempMaxInput: '20' }), [
['space-temp-max', 'space.error_temp_range'],
]);
assert.deepEqual(spaceFields({ fillMode: 'temp', tempMinInput: '21', tempMaxInput: '20' }), [
['space-temp-max', 'space.error_temp_range'],
]);
});
test('#614 spaceDialogProblems validates custom north only and keeps exact bounds', () => {
const northError = [['space-north-deg', 'space.error_north']];
for (const raw of ['', ' ', 'north', '12,5', '-1', '360']) {
assert.deepEqual(spaceFields({ northDeg: 0, northDegInput: raw }), northError, raw);
}
for (const raw of ['0', '359']) {
assert.deepEqual(spaceFields({ northDeg: 0, northDegInput: raw }), [], raw);
}
assert.deepEqual(spaceFields({ northDeg: null, northDegInput: 'not used' }), []);
});
const baseMarker = (patch = {}) => ({
binding: 'virtual',
bindingMode: 'virtual',
name: 'Virtual lamp',
tapAction: 'more-info',
tapTarget: '',
valueBadgeTouched: false,
valueBadgeEnabled: false,
valueBadgeSource: null,
...patch,
});
test('#614 markerProblems exposes virtual name, Run target and badge source inline', () => {
assert.deepEqual(fields(markerProblems(baseMarker({
name: ' ',
tapAction: 'run',
valueBadgeTouched: true,
valueBadgeEnabled: true,
}))), [
['marker-name', 'marker.error_virtual_name'],
['marker-run-target', 'marker.error_run_target'],
['marker-value-badge-source', 'marker.error_value_badge_source'],
]);
assert.deepEqual(fields(markerProblems(baseMarker({ name: 'Lamp' }))), []);
assert.deepEqual(fields(markerProblems(baseMarker({ tapAction: 'run', tapTarget: 'script.good' }))), []);
assert.deepEqual(fields(markerProblems(baseMarker({
valueBadgeTouched: true,
valueBadgeEnabled: true,
valueBadgeSource: { entity: 'sensor.value' },
}))), []);
assert.deepEqual(fields(markerProblems(baseMarker({
valueBadgeTouched: false,
valueBadgeEnabled: true,
valueBadgeSource: null,
}))), []);
});
+1 -1
View File
@@ -23,7 +23,7 @@
"src/devices.ts", "src/device-inbox.ts",
"src/virtual-light-state.ts", "src/config-store.ts", "src/config-reload-authority.ts", "src/config-write-conflict.ts", "src/summary-panel.ts", "src/summary-panel-metrics.ts", "src/summary-panel-i18n.ts", "src/summary-panel-identity.ts", "src/summary-panel-picker.ts", "src/summary-panel-runtime-loaded.ts",
"src/backdrop-probe.ts",
"src/types.ts", "src/editors/dialog-baseline.ts",
"src/types.ts", "src/editors/dialog-baseline.ts", "src/editors/general-form-state.ts", "src/editors/space-form-state.ts", "src/editors/marker-form-state.ts",
"src/space-geometry.ts", "src/junction-limits.ts",
"src/space-order.ts", "src/card-editor-validation.ts",
"src/signing.ts", "src/initial-load.ts", "src/space-model-selection.ts", "src/space-dialog.ts",