refactor(chart): enforce 400-line source limit
Some checks failed
Package component / package (push) Failing after 4m19s

This commit is contained in:
liqiyuan
2026-07-27 15:05:13 +08:00
parent dcc27a88be
commit 082462cf67
61 changed files with 9682 additions and 8407 deletions

View File

@@ -0,0 +1,304 @@
import { flushPromises } from '@vue/test-utils'
import { describe, expect, it } from 'vitest'
import { flushAnimationFrames } from '../../test/setup'
import { gridSeries, mountSizedChart } from '../../test/waveformChart'
describe('WaveformChart', () => {
it('shows Y-axis end values only on the top row in compact mode', async () => {
const wrapper = await mountSizedChart(
{
kind: 'series',
series: [
{
name: 'top-left',
data: {
kind: 'points',
points: [
{ x: 0, y: 0.11 },
{ x: 1, y: 0.89 },
],
},
},
{
name: 'top-right',
data: {
kind: 'points',
points: [
{ x: 0, y: 1.11 },
{ x: 1, y: 1.89 },
],
},
},
{
name: 'bottom-left',
data: {
kind: 'points',
points: [
{ x: 0, y: 2 },
{ x: 1, y: 3 },
],
},
},
{
name: 'bottom-right',
data: {
kind: 'points',
points: [
{ x: 0, y: 4 },
{ x: 1, y: 5 },
],
},
},
],
},
{ displayMode: 'compact', grid: { rowCount: 2, columnCount: 2 } },
)
const tracks = wrapper.findAll('.waveform-chart__track')
const endTicks = tracks.map((track) =>
track.findAll('.waveform-chart__axis--y .tick').filter((tick) => {
const match = tick.attributes('transform')?.match(/translate\(0,\s*([\d.]+)\)/)
return match ? Math.abs(Number(match[1])) <= 1 : false
}),
)
expect(endTicks[0]).toHaveLength(1)
expect(Number(endTicks[0][0].text())).toBe(0.9)
expect(endTicks[1]).toHaveLength(1)
expect(Number(endTicks[1][0].text())).toBe(1.9)
expect(endTicks[2]).toHaveLength(0)
expect(endTicks[3]).toHaveLength(0)
})
it('keeps one separate shared exponent for every compact Y axis', async () => {
const wrapper = await mountSizedChart(
{
kind: 'series',
series: [
{
name: 'large',
data: {
kind: 'points',
points: [
{ x: 0, y: 0 },
{ x: 1, y: 254 },
],
},
},
{
name: 'tiny',
data: {
kind: 'points',
points: [
{ x: 0, y: 0 },
{ x: 1, y: 0.0002 },
],
},
},
],
},
{ displayMode: 'compact' },
)
const axes = wrapper.findAll('.waveform-chart__axis--y')
const exponents = wrapper.findAll('.waveform-chart__axis-exponent--y')
expect(axes).toHaveLength(2)
expect(exponents.map((label) => label.text())).toEqual(['E+02', 'E-04'])
axes.forEach((axis) => {
const labels = axis.findAll('.tick text').map((tick) => tick.text())
expect(labels.every((label) => !label.startsWith('E'))).toBe(true)
expect(labels.every((label) => /^-?\d+\.\d{2}$/.test(label))).toBe(true)
})
})
it('prefers a trimmed series name and falls back to yLabel for unnamed data', async () => {
const namedChart = await mountSizedChart(
{
kind: 'series',
series: [
{
name: ' BT2_2M ',
unit: 'T',
data: { kind: 'points', points: [{ x: 0, y: 1 }] },
},
],
},
{ yLabel: 'T' },
)
const unnamedChart = await mountSizedChart(
{ kind: 'points', points: [{ x: 0, y: 1 }] },
{ yLabel: '自定义幅值' },
)
expect(namedChart.get('.waveform-chart__y-axis-label').text()).toBe('BT2_2M')
expect(unnamedChart.get('.waveform-chart__y-axis-label').text()).toBe('自定义幅值')
})
it('synchronizes every channel tooltip in separated mode and preserves the legacy event', async () => {
const wrapper = await mountSizedChart(
{
kind: 'series',
series: [
{
name: 'BT2_2M',
unit: 'T',
data: {
kind: 'points',
points: [
{ x: 0, y: 1 },
{ x: 1, y: 2 },
],
},
},
{
name: 'BT1_2M',
unit: 'T',
data: {
kind: 'points',
points: [
{ x: 0, y: 3 },
{ x: 1, y: 4 },
],
},
},
],
},
{ displayMode: 'separated' },
)
const overlay = wrapper.get('.waveform-chart__overlay--shared')
Object.defineProperty(overlay.element, 'getBoundingClientRect', {
value: () => ({ left: 0, top: 0, width: 712, height: 290 }),
})
overlay.element.dispatchEvent(
new MouseEvent('pointermove', { clientX: 700, clientY: 120, bubbles: true }),
)
flushAnimationFrames()
await flushPromises()
const tooltip = wrapper.get('.waveform-chart__tooltip')
expect(tooltip.text()).toContain('BT2_2M:')
expect(tooltip.text()).toContain('2 T')
expect(tooltip.text()).toContain('BT1_2M:')
expect(tooltip.text()).toContain('4 T')
const crosshairLines = wrapper.findAll('.waveform-chart__crosshair line')
expect(crosshairLines).toHaveLength(2)
crosshairLines.forEach((line) => {
expect(line.attributes('x1')).toBe(line.attributes('x2'))
expect(line.attributes('y1')).toBe('0')
})
expect(wrapper.find('.waveform-chart__crosshair circle').exists()).toBe(false)
expect(wrapper.emitted('point-hover')?.at(-1)).toEqual([{ x: 1, y: 2 }])
})
it('keeps synchronized hover feedback in compact mode', async () => {
const wrapper = await mountSizedChart(gridSeries(2), { displayMode: 'compact' })
const overlay = wrapper.get('.waveform-chart__overlay--shared')
Object.defineProperty(overlay.element, 'getBoundingClientRect', {
value: () => ({ left: 0, top: 0, width: 712, height: 290 }),
})
overlay.element.dispatchEvent(
new MouseEvent('pointermove', { clientX: 700, clientY: 120, bubbles: true }),
)
flushAnimationFrames()
await flushPromises()
expect(wrapper.findAll('.waveform-chart__crosshair line')).toHaveLength(2)
expect(wrapper.findAll('.waveform-chart__tooltip-series')).toHaveLength(2)
expect(wrapper.emitted('point-hover')?.at(-1)).toEqual([{ x: 1, y: 1 }])
})
it('keeps separated tracks apart while sharing one x-axis and one interaction layer', async () => {
const wrapper = await mountSizedChart(
{
kind: 'series',
series: [
{
name: 'A',
data: {
kind: 'points',
points: [
{ x: 0, y: 0 },
{ x: 2, y: 1 },
],
},
},
{
name: 'B',
data: {
kind: 'points',
points: [
{ x: 0, y: 10 },
{ x: 2, y: 20 },
],
},
},
],
},
{ displayMode: 'separated' },
)
const tracks = wrapper.findAll('.waveform-chart__track')
const firstTop = Number(tracks[0].attributes('data-track-top'))
const firstHeight = Number(tracks[0].attributes('data-track-height'))
const secondTop = Number(tracks[1].attributes('data-track-top'))
expect(wrapper.findAll('.waveform-chart__svg')).toHaveLength(1)
expect(wrapper.findAll('.waveform-chart__axis--x')).toHaveLength(1)
expect(wrapper.findAll('.waveform-chart__axis--y')).toHaveLength(2)
expect(wrapper.findAll('.waveform-chart__y-axis-label').map((label) => label.text())).toEqual([
'A',
'B',
])
expect(wrapper.findAll('.waveform-chart__overlay--shared')).toHaveLength(1)
expect(secondTop).toBeGreaterThan(firstTop + firstHeight)
})
it('joins compact tracks without a gap and keeps only the bottom x-axis', async () => {
const wrapper = await mountSizedChart(
{
kind: 'series',
series: [
{
name: 'A',
data: {
kind: 'points',
points: [
{ x: 0, y: -1 },
{ x: 1, y: 1 },
],
},
},
{
name: 'B',
data: {
kind: 'points',
points: [
{ x: 0, y: 100 },
{ x: 1, y: 200 },
],
},
},
],
},
{ displayMode: 'compact' },
)
const tracks = wrapper.findAll('.waveform-chart__track')
const firstTop = Number(tracks[0].attributes('data-track-top'))
const firstHeight = Number(tracks[0].attributes('data-track-height'))
const secondTop = Number(tracks[1].attributes('data-track-top'))
expect(wrapper.attributes('data-display-mode')).toBe('compact')
expect(wrapper.findAll('.waveform-chart__axis--x')).toHaveLength(1)
expect(wrapper.findAll('.waveform-chart__y-axis-label').map((label) => label.text())).toEqual([
'A',
'B',
])
expect(secondTop).toBeCloseTo(firstTop + firstHeight, 6)
expect(wrapper.findAll('.waveform-chart__axis--y')[0].text()).not.toBe(
wrapper.findAll('.waveform-chart__axis--y')[1].text(),
)
})
})