blob: 2f3ab18bea56f6ffa2615dc80a8d7d61e698d60d [file] [edit]
import './plot-summary-v2-sk';
import { PlotSummaryV2Sk } from './plot-summary-v2-sk';
import { expect } from 'chai';
import { TraceSeries } from './trace-types';
describe('plot-summary-v2-sk', () => {
let element: PlotSummaryV2Sk;
beforeEach(async () => {
element = document.createElement('plot-summary-v2-sk') as PlotSummaryV2Sk;
document.body.appendChild(element);
await element.updateComplete;
});
afterEach(() => {
document.body.removeChild(element);
});
it('instantiates the component with skeletal markup', () => {
const container = element.shadowRoot!.querySelector('.summary-container');
expect(container).to.not.be.null;
const canvas = element.shadowRoot!.querySelector('canvas');
expect(canvas).to.not.be.null;
const box = element.shadowRoot!.querySelector('h-resizable-box-sk');
expect(box).to.not.be.null;
});
it('does not throw when drawing empty series', () => {
element.series = [];
expect(() => element.drawSummary()).to.not.throw();
});
it('decimates trace rows correctly using min-max bucket when points exceed limit', () => {
const rows = [];
for (let i = 0; i < 1000; i++) {
rows.push({ commit_number: i, val: i % 2 === 0 ? 10 : 100, createdat: i * 1000 });
}
const decimated = (element as any).decimate(rows);
expect(decimated.length).to.be.below(rows.length);
expect(decimated.length).to.be.at.most(1000);
});
it('draws trace lines on the canvas for date domain', async () => {
const canvas = element.shadowRoot!.querySelector('canvas') as HTMLCanvasElement;
canvas.getBoundingClientRect = () => ({ left: 0, top: 0, width: 200, height: 45 }) as DOMRect;
const series: TraceSeries[] = [
{
id: 'trace1',
color: '#ff0000',
rows: [
{ commit_number: 10, val: 50, createdat: 1000 },
{ commit_number: 20, val: 150, createdat: 2000 },
],
},
];
element.domain = 'date';
element.series = series;
await element.updateComplete;
const ctx = canvas.getContext('2d')!;
const spyLines: { x: number; y: number; type: string }[] = [];
const oldMoveTo = ctx.moveTo;
const oldLineTo = ctx.lineTo;
ctx.moveTo = function (x: number, y: number) {
spyLines.push({ x, y, type: 'moveTo' });
oldMoveTo.call(ctx, x, y);
};
ctx.lineTo = function (x: number, y: number) {
spyLines.push({ x, y, type: 'lineTo' });
oldLineTo.call(ctx, x, y);
};
try {
element.drawSummary();
expect(spyLines.length).to.equal(2);
expect(spyLines[0].type).to.equal('moveTo');
expect(spyLines[0].x).to.equal(0);
expect(spyLines[1].type).to.equal('lineTo');
expect(spyLines[1].x).to.equal(200);
} finally {
ctx.moveTo = oldMoveTo;
ctx.lineTo = oldLineTo;
}
});
it('aligns plot points when evenXAxisSpacing is enabled', async () => {
const canvas = element.shadowRoot!.querySelector('canvas') as HTMLCanvasElement;
canvas.getBoundingClientRect = () => ({ left: 0, top: 0, width: 200, height: 45 }) as DOMRect;
const series: TraceSeries[] = [
{
id: 'trace1',
color: '#ff0000',
rows: [
{ commit_number: 10, val: 50, createdat: 1000 },
{ commit_number: 20, val: 100, createdat: 2000 },
{ commit_number: 100, val: 50, createdat: 3000 },
],
},
];
element.evenXAxisSpacing = true;
element.domain = 'commit';
element.series = series;
await element.updateComplete;
const ctx = canvas.getContext('2d')!;
const spyPoints: number[] = [];
const oldMoveTo = ctx.moveTo;
const oldLineTo = ctx.lineTo;
ctx.moveTo = function (x: number, y: number) {
spyPoints.push(x);
oldMoveTo.call(ctx, x, y);
};
ctx.lineTo = function (x: number, y: number) {
spyPoints.push(x);
oldLineTo.call(ctx, x, y);
};
try {
element.drawSummary();
expect(spyPoints.length).to.equal(3);
const spacing1 = spyPoints[1] - spyPoints[0];
const spacing2 = spyPoints[2] - spyPoints[1];
expect(Math.abs(spacing1 - spacing2)).to.be.below(1);
} finally {
ctx.moveTo = oldMoveTo;
ctx.lineTo = oldLineTo;
}
});
it('converts domain values to pixel coords correctly when evenXAxisSpacing is enabled', async () => {
element.series = [
{
id: 'trace1',
color: '#ff0000',
rows: [
{ commit_number: 10, val: 50, createdat: 1000 },
{ commit_number: 20, val: 100, createdat: 2000 },
{ commit_number: 100, val: 50, createdat: 3000 },
],
},
];
element.evenXAxisSpacing = true;
element.domain = 'commit';
await element.updateComplete;
// Width = 200px. Unique commits: 10 (idx 0), 20 (idx 1), 100 (idx 2).
// viewportMinX=20 (idx 1, 100px), viewportMaxX=100 (idx 2, 200px)
const coords = (element as any).convertToCoordsRange(20, 100, 200);
expect(coords).to.not.be.null;
expect(coords!.begin).to.equal(100);
expect(coords!.end).to.equal(200);
});
it('converts pixel coords to domain values correctly when evenXAxisSpacing is enabled', async () => {
element.series = [
{
id: 'trace1',
color: '#ff0000',
rows: [
{ commit_number: 10, val: 50, createdat: 1000 },
{ commit_number: 20, val: 100, createdat: 2000 },
{ commit_number: 100, val: 50, createdat: 3000 },
],
},
];
element.evenXAxisSpacing = true;
element.domain = 'commit';
await element.updateComplete;
// Width = 200px. 0px -> idx 0 (commit 10), 100px -> idx 1 (commit 20), 200px -> idx 2 (commit 100).
const values = (element as any).convertToValueRange(100, 200, 200);
expect(values).to.not.be.null;
expect(values!.begin).to.equal(20);
expect(values!.end).to.equal(100);
});
it('handles out-of-bounds coordinate and value conversions when evenXAxisSpacing is enabled', async () => {
element.series = [
{
id: 'trace1',
color: '#ff0000',
rows: [
{ commit_number: 10, val: 50, createdat: 1000 },
{ commit_number: 20, val: 100, createdat: 2000 },
],
},
];
element.evenXAxisSpacing = true;
element.domain = 'commit';
await element.updateComplete;
// arr = [10, 20], step = 10. width = 100px (0px=10, 100px=20).
// -50px should map to virtIdx = -0.5 -> commit 5.
const values = (element as any).convertToValueRange(-50, 150, 100);
expect(values).to.not.be.null;
expect(values!.begin).to.equal(5);
expect(values!.end).to.equal(25);
// Commit 0 (virtIdx = -1.0) should map to -100px. Commit 30 (virtIdx = 2.0) should map to 200px.
const coords = (element as any).convertToCoordsRange(0, 30, 100);
expect(coords).to.not.be.null;
expect(coords!.begin).to.equal(-100);
expect(coords!.end).to.equal(200);
});
});