110 lines
3.7 KiB
TypeScript
110 lines
3.7 KiB
TypeScript
import { describe, it, expect } from 'vitest'
|
||
import { niceDomain, fmtTick } from '../src/components/editor/chart-domain'
|
||
|
||
describe('niceDomain', () => {
|
||
// 已确诊 bug 场景:数据全挤 97~98,旧实现映射到 [0,98] 导致折线贴顶
|
||
it('高基线小波动:line 值域收紧为数据带,折线不贴顶', () => {
|
||
const d = niceDomain([97, 98, 97.6, 97, 98])
|
||
// 波动 <10% → domain = [97 - 1.5, 98 + 1.5],step 0.5 → [95.5, 99.5]
|
||
expect(d.min).toBeLessThan(97)
|
||
expect(d.max).toBeGreaterThan(98)
|
||
expect(d.max - d.min).toBeLessThan(10)
|
||
})
|
||
|
||
it('高基线小波动:ticks 4~5 个且为整数步长', () => {
|
||
const d = niceDomain([97, 98, 97.6, 97, 98])
|
||
expect(d.ticks.length).toBeGreaterThanOrEqual(4)
|
||
expect(d.ticks.length).toBeLessThanOrEqual(6)
|
||
const step = d.ticks[1] - d.ticks[0]
|
||
expect(step).toBe(1)
|
||
// 首尾与 domain 对齐
|
||
expect(d.ticks[0]).toBe(d.min)
|
||
expect(d.ticks[d.ticks.length - 1]).toBe(d.max)
|
||
})
|
||
|
||
it('bar 类保持 0 基线(不因数据全大而从数据 min 起)', () => {
|
||
const d = niceDomain([97, 98, 97.6, 97, 98], { zeroBase: true })
|
||
expect(d.min).toBe(0)
|
||
expect(d.ticks[0]).toBe(0)
|
||
expect(d.max).toBeGreaterThanOrEqual(98)
|
||
})
|
||
|
||
it('常规整数数据 [1,2,3] → nice 步长(0.5 或 1),刻度覆盖 max', () => {
|
||
const d = niceDomain([1, 2, 3])
|
||
const step = d.ticks[1] - d.ticks[0]
|
||
expect([0.5, 1]).toContain(step)
|
||
expect(d.ticks).toContain(3)
|
||
})
|
||
|
||
it('小数值数据 [0.1, 0.2] → 步长 0.5,下限 0.5 生效', () => {
|
||
const d = niceDomain([0.1, 0.2])
|
||
expect(d.ticks[1] - d.ticks[0]).toBe(0.5)
|
||
expect(d.min).toBeLessThanOrEqual(0.1)
|
||
expect(d.max).toBeGreaterThanOrEqual(0.2)
|
||
})
|
||
|
||
it('单值数据不产生除零/NaN', () => {
|
||
const d = niceDomain([5])
|
||
expect(d.min).toBeLessThan(d.max)
|
||
expect(Number.isFinite(d.min)).toBe(true)
|
||
expect(Number.isFinite(d.max)).toBe(true)
|
||
expect(d.ticks.length).toBeGreaterThanOrEqual(3)
|
||
})
|
||
|
||
it('全等值数据 line 值域仍为区间而非单点', () => {
|
||
const d = niceDomain([42, 42, 42, 42])
|
||
expect(d.max).toBeGreaterThan(d.min)
|
||
expect(d.ticks.length).toBeGreaterThanOrEqual(3)
|
||
})
|
||
|
||
it('全等值数据 bar 类 → [0, ≥value]', () => {
|
||
const d = niceDomain([42, 42, 42], { zeroBase: true })
|
||
expect(d.min).toBe(0)
|
||
expect(d.max).toBeGreaterThanOrEqual(42)
|
||
})
|
||
|
||
it('maxCap 作为上限覆盖(仅当 > 数据 max)', () => {
|
||
const d = niceDomain([1, 2, 3], { zeroBase: true, maxCap: 100 })
|
||
expect(d.max).toBeGreaterThanOrEqual(100)
|
||
})
|
||
|
||
it('maxCap 小于数据 max 时不收紧值域', () => {
|
||
const d = niceDomain([1, 2, 3], { zeroBase: true, maxCap: 1 })
|
||
expect(d.max).toBeGreaterThanOrEqual(3)
|
||
})
|
||
|
||
it('空数据返回安全默认值域', () => {
|
||
const d = niceDomain([])
|
||
expect(d.max).toBeGreaterThan(d.min)
|
||
expect(d.ticks.length).toBeGreaterThanOrEqual(2)
|
||
})
|
||
|
||
it('过滤 NaN/Infinity', () => {
|
||
const d = niceDomain([NaN, Infinity, -Infinity, 5, 10])
|
||
expect(d.min).toBeLessThanOrEqual(5)
|
||
expect(d.max).toBeGreaterThanOrEqual(10)
|
||
})
|
||
|
||
it('大整数数据步长取 5×10^k', () => {
|
||
const d = niceDomain([1000, 1200, 1500, 2000], { zeroBase: true })
|
||
const step = d.ticks[1] - d.ticks[0]
|
||
expect(step).toBeGreaterThan(0)
|
||
// 2000 跨度 → 步长 500 或 1000 之类 nice 数
|
||
expect([100, 200, 500, 1000].includes(step)).toBe(true)
|
||
})
|
||
})
|
||
|
||
describe('fmtTick', () => {
|
||
it('去尾零', () => {
|
||
expect(fmtTick(2.5)).toBe('2.5')
|
||
expect(fmtTick(20)).toBe('20')
|
||
expect(fmtTick(0)).toBe('0')
|
||
expect(fmtTick(97.6)).toBe('97.6')
|
||
})
|
||
|
||
it('消浮点误差', () => {
|
||
expect(fmtTick(0.1 + 0.2)).toBe('0.3')
|
||
expect(fmtTick(2.55)).toBe('2.55')
|
||
})
|
||
})
|