Add host temperature telemetry and history
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
import { afterEach, expect, it } from 'vitest';
|
||||
import { flushSync, mount, unmount } from 'svelte';
|
||||
import TemperatureChart from '../../src/lib/ui/components/capacity/TemperatureChart.svelte';
|
||||
import type { CapacityHistory } from '../../src/lib/capacity.js';
|
||||
|
||||
let component: ReturnType<typeof mount> | undefined;
|
||||
afterEach(async () => {
|
||||
if (component) await unmount(component);
|
||||
component = undefined;
|
||||
document.body.replaceChildren();
|
||||
});
|
||||
function history(): CapacityHistory {
|
||||
return {
|
||||
range: '1h',
|
||||
startAt: 1000,
|
||||
endAt: 4000,
|
||||
bucketMs: 1000,
|
||||
points: [1000, 2000, 3000].map((at) => ({
|
||||
at,
|
||||
cpuCoresAvailable: null,
|
||||
memoryBytesAvailable: null,
|
||||
reportingHosts: 0,
|
||||
expectedHosts: 1
|
||||
})),
|
||||
temperatures: [
|
||||
{
|
||||
id: 'host:cpu',
|
||||
hostId: 'host',
|
||||
label: 'CPU temperature',
|
||||
kind: 'cpu',
|
||||
points: [65, null, 67].map((celsius, i) => ({ at: 1000 + i * 1000, celsius }))
|
||||
},
|
||||
{
|
||||
id: 'host:drive',
|
||||
hostId: 'host',
|
||||
label: 'NVMe drive 1',
|
||||
kind: 'nvme',
|
||||
points: [49, 50.9, 52].map((celsius, i) => ({ at: 1000 + i * 1000, celsius }))
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
function show(report = history()) {
|
||||
component = mount(TemperatureChart, {
|
||||
target: document.body,
|
||||
props: { history: report, scope: 'ec-2' }
|
||||
});
|
||||
flushSync();
|
||||
}
|
||||
|
||||
it('defaults to CPU and toggles device lines and readouts together', () => {
|
||||
show();
|
||||
const buttons = document.querySelectorAll<HTMLButtonElement>('.legend button');
|
||||
expect(buttons[0].getAttribute('aria-pressed')).toBe('true');
|
||||
expect(buttons[1].getAttribute('aria-pressed')).toBe('false');
|
||||
expect(document.querySelectorAll('[data-series]')).toHaveLength(1);
|
||||
// A missing middle bucket splits the CPU line into two isolated segments.
|
||||
expect(document.querySelectorAll('[data-series="host:cpu"] path')).toHaveLength(2);
|
||||
buttons[1].click();
|
||||
flushSync();
|
||||
expect(document.querySelectorAll('[data-series]')).toHaveLength(2);
|
||||
expect(document.querySelector('.readout')?.textContent).toContain('52 °C');
|
||||
buttons[0].click();
|
||||
buttons[1].click();
|
||||
flushSync();
|
||||
expect(document.querySelectorAll('[data-series]')).toHaveLength(0);
|
||||
expect(document.body.textContent).toContain('Select a sensor to show history');
|
||||
expect(document.querySelector('.readout')).toBeNull();
|
||||
});
|
||||
|
||||
it('supports keyboard and pointer inspection without turning missing readings into zero', () => {
|
||||
show();
|
||||
const plot = document.querySelector<HTMLElement>('[role="slider"]')!;
|
||||
expect(plot.getAttribute('aria-valuenow')).toBe('2');
|
||||
plot.dispatchEvent(new KeyboardEvent('keydown', { key: 'Home', bubbles: true }));
|
||||
flushSync();
|
||||
expect(plot.getAttribute('aria-valuetext')).toContain('65 °C');
|
||||
plot.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight', bubbles: true }));
|
||||
flushSync();
|
||||
expect(plot.getAttribute('aria-valuetext')).toContain('Unavailable');
|
||||
expect(document.querySelector('.readout')?.textContent).not.toContain('0 °C');
|
||||
Object.defineProperty(plot, 'getBoundingClientRect', {
|
||||
value: () => ({ left: 0, width: 1000 })
|
||||
});
|
||||
plot.dispatchEvent(
|
||||
new PointerEvent('pointerdown', { clientX: 8, pointerType: 'touch', bubbles: true })
|
||||
);
|
||||
flushSync();
|
||||
expect(plot.getAttribute('aria-valuenow')).toBe('0');
|
||||
expect(document.querySelector('.readout')?.textContent).toContain('65 °C');
|
||||
});
|
||||
|
||||
it('shows unsupported hosts as unavailable', () => {
|
||||
const report = history();
|
||||
report.temperatures[0].points = report.temperatures[0].points.map((point) => ({
|
||||
...point,
|
||||
celsius: null
|
||||
}));
|
||||
show(report);
|
||||
expect(document.body.textContent).toContain('No temperature readings in this period');
|
||||
expect(document.body.textContent).toContain('Unavailable');
|
||||
});
|
||||
|
||||
it('plots a genuine zero-degree reading', () => {
|
||||
const report = history();
|
||||
report.temperatures[0].points[2].celsius = 0;
|
||||
show(report);
|
||||
expect(document.querySelector('.readout')?.textContent).toContain('0 °C');
|
||||
expect(document.querySelector('.empty-chart')).toBeNull();
|
||||
});
|
||||
Reference in New Issue
Block a user