Spaces:
Sleeping
Sleeping
| import { describe, it, expect, afterEach } from 'vitest'; | |
| import { | |
| GLOBAL_SPATIAL_DEFAULTS, | |
| SPATIAL_DEFAULT_OVERRIDES, | |
| resolveSpatialDefaults, | |
| } from '../src/ui/spatialSliderDefaults.js'; | |
| describe('resolveSpatialDefaults', () => { | |
| /** @type {Array<{ key: string, previous: object|undefined }>} */ | |
| const savedKeys = []; | |
| afterEach(() => { | |
| for (const { key, previous } of savedKeys.splice(0)) { | |
| if (previous === undefined) { | |
| delete SPATIAL_DEFAULT_OVERRIDES[key]; | |
| } else { | |
| SPATIAL_DEFAULT_OVERRIDES[key] = previous; | |
| } | |
| } | |
| }); | |
| function setOverride(key, partial) { | |
| savedKeys.push({ | |
| key, | |
| previous: SPATIAL_DEFAULT_OVERRIDES[key] | |
| ? { ...SPATIAL_DEFAULT_OVERRIDES[key] } | |
| : undefined, | |
| }); | |
| SPATIAL_DEFAULT_OVERRIDES[key] = partial; | |
| } | |
| it('returns global mid defaults when no overrides exist', () => { | |
| const d = resolveSpatialDefaults({ | |
| workspaceMode: 'ARITHMETIC', | |
| viewMode: 'NAVIGATION', | |
| renderMode: 'RIBBONS', | |
| }); | |
| expect(d.threadSpacing).toBe(GLOBAL_SPATIAL_DEFAULTS.threadSpacing); | |
| expect(d.threadVectorDistance).toBe(GLOBAL_SPATIAL_DEFAULTS.threadVectorDistance); | |
| expect(d.threadAmplitudeY).toBe(GLOBAL_SPATIAL_DEFAULTS.threadAmplitudeY); | |
| expect(d.threadWidth).toBe(GLOBAL_SPATIAL_DEFAULTS.threadWidth); | |
| expect(d.threadThickness).toBe(GLOBAL_SPATIAL_DEFAULTS.threadThickness); | |
| expect(d.threadSpacingY).toBe(d.threadVectorDistance); | |
| }); | |
| it('applies workspace → view → render layers (more specific wins)', () => { | |
| setOverride('ARITHMETIC', { threadSpacing: 0.5 }); | |
| setOverride('ARITHMETIC|NAVIGATION', { threadAmplitudeY: 9.0 }); | |
| setOverride('ARITHMETIC|NAVIGATION|POINTS', { threadThickness: 0.12 }); | |
| const d = resolveSpatialDefaults({ | |
| workspaceMode: 'ARITHMETIC', | |
| viewMode: 'NAVIGATION', | |
| renderMode: 'POINTS', | |
| }); | |
| expect(d.threadSpacing).toBe(0.5); | |
| expect(d.threadAmplitudeY).toBe(9.0); | |
| expect(d.threadThickness).toBe(0.12); | |
| expect(d.threadWidth).toBe(GLOBAL_SPATIAL_DEFAULTS.threadWidth); | |
| }); | |
| it('does not leak overrides from a different context', () => { | |
| setOverride('COMPARE|ANALYSIS|POINTS', { threadWidth: 0.25 }); | |
| const d = resolveSpatialDefaults({ | |
| workspaceMode: 'ARITHMETIC', | |
| viewMode: 'NAVIGATION', | |
| renderMode: 'POINTS', | |
| }); | |
| expect(d.threadWidth).toBe(GLOBAL_SPATIAL_DEFAULTS.threadWidth); | |
| }); | |
| it('applies captured ARITHMETIC|ANALYSIS|POINTS preset (Amplitude 40)', () => { | |
| // Production override lives in SPATIAL_DEFAULT_OVERRIDES — assert the seam. | |
| const d = resolveSpatialDefaults({ | |
| workspaceMode: 'ARITHMETIC', | |
| viewMode: 'ANALYSIS', | |
| renderMode: 'POINTS', | |
| }); | |
| expect(d.threadSpacing).toBe(0.4); | |
| expect(d.threadVectorDistance).toBe(10.0); | |
| expect(d.threadAmplitudeY).toBe(40.0); | |
| expect(d.threadWidth).toBe(0.2); | |
| expect(d.threadThickness).toBe(0.05); | |
| }); | |
| it('applies captured COMPARE|NAVIGATION|POINTS preset', () => { | |
| const d = resolveSpatialDefaults({ | |
| workspaceMode: 'COMPARE', | |
| viewMode: 'NAVIGATION', | |
| renderMode: 'POINTS', | |
| }); | |
| expect(d.threadSpacing).toBe(0.7); | |
| expect(d.threadVectorDistance).toBe(10.0); | |
| expect(d.threadAmplitudeY).toBe(4.9); | |
| expect(d.threadWidth).toBe(0.1); | |
| expect(d.threadThickness).toBe(0.01); | |
| }); | |
| it('applies COMPARE|ANALYSIS|POINTS preset with Amplitude 16', () => { | |
| const d = resolveSpatialDefaults({ | |
| workspaceMode: 'COMPARE', | |
| viewMode: 'ANALYSIS', | |
| renderMode: 'POINTS', | |
| }); | |
| expect(d.threadSpacing).toBe(1.45); | |
| expect(d.threadVectorDistance).toBe(1.0); | |
| expect(d.threadAmplitudeY).toBe(16.0); | |
| expect(d.threadWidth).toBe(0.2); | |
| expect(d.threadThickness).toBe(0.01); | |
| }); | |
| it('applies COMPARE|ANALYSIS|RIBBONS twin with Amplitude 16', () => { | |
| const d = resolveSpatialDefaults({ | |
| workspaceMode: 'COMPARE', | |
| viewMode: 'ANALYSIS', | |
| renderMode: 'RIBBONS', | |
| }); | |
| expect(d.threadAmplitudeY).toBe(16.0); | |
| expect(d.threadSpacing).toBe(1.45); | |
| expect(d.threadVectorDistance).toBe(1.0); | |
| }); | |
| it('applies captured COMPARE|NAVIGATION|RIBBONS preset', () => { | |
| const d = resolveSpatialDefaults({ | |
| workspaceMode: 'COMPARE', | |
| viewMode: 'NAVIGATION', | |
| renderMode: 'RIBBONS', | |
| }); | |
| expect(d.threadSpacing).toBe(1.55); | |
| expect(d.threadVectorDistance).toBe(10.0); | |
| expect(d.threadAmplitudeY).toBe(7.0); | |
| expect(d.threadWidth).toBe(0.057); | |
| expect(d.threadThickness).toBe(0.05); | |
| }); | |
| }); | |