/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-return */
import { expect, fixture, html } from '@open-wc/testing';
import ZnChart from './chart.component';
ZnChart.define('zn-chart-live-test');
class Source extends EventTarget {
static instances: Source[]=[]; closed=false; onopen?:()=>void; onerror?:()=>void;
url: string;
constructor(url: string) { super(); this.url = url;Source.instances.push(this); }
close() {this.closed=true;}
send(event:string,frame:unknown) {this.dispatchEvent(new MessageEvent(event,{data:JSON.stringify(frame)}));}
}
const pause=()=>new Promise(r=>setTimeout(r,50));
describe('chart SSE component',()=>{
const original=window.EventSource;
beforeEach(()=>{Source.instances=[];window.EventSource=Source as unknown as typeof EventSource;});
afterEach(()=>{window.EventSource=original;});
it('renders SSE buckets and expected bands, reacts to display changes, and stops when removed',async()=>{
const el:any=await fixture(html``);
await el.updateComplete;await pause();
const source=Source.instances.at(-1)!;
expect(source).to.exist;
const f={from:0,until:10000,server_time:Date.now(),expires_at:Date.now()+60000,resolution_seconds:1,metric:'hits',points:[{at:1000,value:0},{at:2000,value:2}],prediction:{status:'ready',points:[{at:0,lower:1,upper:5,expected:3,available:true}]}};
source.send('snapshot',f);await el.updateComplete;
expect(el.chart.getOption().series.length).to.equal(3);
expect(el.chart.getOption().series[2].data.map((p:any)=>p.value)).to.deep.equal([[1000,0],[2000,2]]);
const valueModel = el.chart.getModel().getSeriesByIndex(2);
const axisModel = el.chart.getModel().getComponent('xAxis',0);
expect(valueModel.get('animation')).to.equal(true);
expect(valueModel.get('animationDuration')).to.equal(0);
expect(valueModel.get('animationDurationUpdate')).to.equal(350);
expect(valueModel.get('animationThreshold')).to.equal(10000);
const rangeModel = el.chart.getModel().getSeriesByIndex(1);
const rangeData = rangeModel.option.data;
expect(rangeModel.id).to.equal('live-range');
expect(rangeModel.get('animation')).to.equal(true);
expect(rangeModel.get('animationDuration')).to.equal(0);
el.hideZero=true;await el.updateComplete;await el.updateComplete;
expect(el.chart.getOption().series[2].data[0].value[1]).to.equal(null);
source.send('delta',{...f,prediction:undefined,points:[{at:2000,value:7}]});await el.updateComplete;
expect(el.chart.getOption().series[2].data[1].value[1]).to.equal(7);
expect(el.chart.getViewOfSeriesModel(valueModel)._polyline.animators.length).to.be.greaterThan(0);
const sameAxis = el.chart.getModel().getComponent('xAxis',0) === axisModel;
const sameValues = el.chart.getModel().getSeriesByIndex(2) === valueModel;
expect(sameAxis).to.equal(true);
expect(sameValues).to.equal(true);
const sameModel = el.chart.getModel().getSeriesByIndex(1) === rangeModel;
expect(sameModel).to.equal(true);
const sameSource = el.chart.getModel().getSeriesByIndex(1).option.data === rangeData;
expect(sameSource).to.equal(true);
source.send('heartbeat',{server_time:f.server_time+1000,expires_at:f.expires_at});await el.updateComplete;
const sameHeartbeatSource = el.chart.getModel().getSeriesByIndex(1).option.data === rangeData;
expect(sameHeartbeatSource).to.equal(true);
source.send('snapshot',{...f,prediction:undefined,points:[]});await el.updateComplete;
expect(el.chart.getModel().getSeries().length).to.equal(1);
el.remove();expect(source.closed).to.equal(true);
});
it('keeps transitions enabled for a high-volume hour', async()=>{
const el:any=await fixture(html``);
await el.updateComplete;await pause();
Source.instances.at(-1)!.send('snapshot',{
from:0,until:3600000,server_time:Date.now(),expires_at:Date.now()+60000,resolution_seconds:1,metric:'average',
points:Array.from({length:3600},(_,i)=>({at:i*1000,value:10+i%3})),
});
await el.updateComplete;
const model=el.chart.getModel().getSeriesByIndex(0);
expect(model.getData().count()).to.equal(3600);
expect(model.isAnimationEnabled()).to.equal(true);
expect(model.get('animationDuration')).to.equal(0);
el.remove();
});
it('restarts transport when its URL changes and when reattached',async()=>{
const el:any=await fixture(html``);
await el.updateComplete;await pause();
const old=Source.instances.at(-1)!;
el.streamUrl='https://relay.example/b';await el.updateComplete;
expect(old.closed).to.equal(true);expect(Source.instances.at(-1)!.url).to.include('/b');
const parent=el.parentElement;el.remove();parent.append(el);await el.updateComplete;await pause();
expect(Source.instances.at(-1)!.closed).to.equal(false);el.remove();
});
});