Add sanity check for source origin in WebLoaderStrategy::startPingLoad()
[WebKit-https.git] / Websites / perf.webkit.org / browser-tests / interactive-time-series-chart-tests.js
1
2 describe('InteractiveTimeSeriesChart', () => {
3
4     it('should change the unlocked indicator to the point closest to the last mouse move position', () => {
5         const context = new BrowsingContext();
6         return ChartTest.importChartScripts(context).then(() => {
7             const chart = ChartTest.createInteractiveChartWithSampleCluster(context);
8
9             chart.setDomain(ChartTest.sampleCluster.startTime, ChartTest.sampleCluster.endTime);
10             chart.fetchMeasurementSets();
11             ChartTest.respondWithSampleCluster(context.symbols.MockRemoteAPI.requests[0]);
12
13             const indicatorChangeCalls = [];
14             chart.listenToAction('indicatorChange', (...args) => indicatorChangeCalls.push(args));
15
16             let selectionChangeCount = 0;
17             chart.listenToAction('selectionChange', () => selectionChangeCount++);
18
19             let canvas;
20             return waitForComponentsToRender(context).then(() => {
21                 expect(chart.currentSelection()).to.be(null);
22                 expect(chart.currentIndicator()).to.be(null);
23                 expect(indicatorChangeCalls).to.be.eql([]);
24
25                 canvas = chart.content().querySelector('canvas');
26                 const rect = canvas.getBoundingClientRect();
27                 canvas.dispatchEvent(new MouseEvent('mousemove', {target: canvas, clientX: rect.right - 1, clientY: rect.top + rect.height / 2, composed: true, bubbles: true}));
28
29                 CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
30                 return waitForComponentsToRender(context);
31             }).then(() => {
32                 expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(true);
33
34                 expect(chart.currentSelection()).to.be(null);
35                 const indicator = chart.currentIndicator();
36                 expect(indicator).to.not.be(null);
37                 const currentView = chart.sampledTimeSeriesData('current');
38                 const lastPoint = currentView.lastPoint();
39                 expect(indicator.view).to.be(currentView);
40                 expect(indicator.point).to.be(lastPoint);
41                 expect(indicator.isLocked).to.be(false);
42                 expect(indicatorChangeCalls).to.be.eql([[lastPoint.id, false]]);
43
44                 expect(selectionChangeCount).to.be(0);
45             });
46         });
47     });
48
49     it('should lock the indicator to the point closest to the clicked position', () => {
50         const context = new BrowsingContext();
51         return ChartTest.importChartScripts(context).then(() => {
52             const chart = ChartTest.createInteractiveChartWithSampleCluster(context);
53
54             chart.setDomain(ChartTest.sampleCluster.startTime, ChartTest.sampleCluster.endTime);
55             chart.fetchMeasurementSets();
56             ChartTest.respondWithSampleCluster(context.symbols.MockRemoteAPI.requests[0]);
57
58             const indicatorChangeCalls = [];
59             chart.listenToAction('indicatorChange', (...args) => indicatorChangeCalls.push(args));
60
61             let selectionChangeCount = 0;
62             chart.listenToAction('selectionChange', () => selectionChangeCount++);
63
64             let canvas;
65             return waitForComponentsToRender(context).then(() => {
66                 expect(chart.currentSelection()).to.be(null);
67                 expect(chart.currentIndicator()).to.be(null);
68                 expect(indicatorChangeCalls).to.be.eql([]);
69                 canvas = chart.content().querySelector('canvas');
70                 const rect = canvas.getBoundingClientRect();
71
72                 const x = rect.right - 1;
73                 const y = rect.top + rect.height / 2;
74                 canvas.dispatchEvent(new MouseEvent('mousemove', {target: canvas, clientX: x, clientY: y, composed: true, bubbles: true}));
75                 canvas.dispatchEvent(new MouseEvent('mousedown', {target: canvas, clientX: x, clientY: y, composed: true, bubbles: true}));
76                 canvas.dispatchEvent(new MouseEvent('mousemove', {target: canvas, clientX: x - 0.5, clientY: y + 0.5, composed: true, bubbles: true}));
77                 canvas.dispatchEvent(new MouseEvent('mouseup', {target: canvas, clientX: x - 0.5, clientY: y + 0.5, composed: true, bubbles: true}));
78                 canvas.dispatchEvent(new MouseEvent('click', {target: canvas, clientX: x - 0.5, clientY: y + 0.5, composed: true, bubbles: true}));
79
80                 CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
81                 return waitForComponentsToRender(context);
82             }).then(() => {
83                 expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(true);
84
85                 const currentView = chart.sampledTimeSeriesData('current');
86                 const lastPoint = currentView.lastPoint();
87                 expect(chart.currentSelection()).to.be(null);
88                 const indicator = chart.currentIndicator();
89                 expect(indicator.view).to.be(currentView);
90                 expect(indicator.point).to.be(lastPoint);
91                 expect(indicator.isLocked).to.be(true);
92                 expect(indicatorChangeCalls).to.be.eql([[lastPoint.id, false], [lastPoint.id, true]]);
93
94                 expect(selectionChangeCount).to.be(0);
95             });
96         });
97     });
98
99     it('should clear the unlocked indicator when the mouse cursor exits the chart', () => {
100         const context = new BrowsingContext();
101         return ChartTest.importChartScripts(context).then(() => {
102             const chart = ChartTest.createInteractiveChartWithSampleCluster(context);
103
104             chart.setDomain(ChartTest.sampleCluster.startTime, ChartTest.sampleCluster.endTime);
105             chart.fetchMeasurementSets();
106             ChartTest.respondWithSampleCluster(context.symbols.MockRemoteAPI.requests[0]);
107
108             const indicatorChangeCalls = [];
109             chart.listenToAction('indicatorChange', (...args) => indicatorChangeCalls.push(args));
110
111             let selectionChangeCount = 0;
112             chart.listenToAction('selectionChange', () => selectionChangeCount++);
113
114             let canvas;
115             let rect;
116             let lastPoint;
117             return waitForComponentsToRender(context).then(() => {
118                 expect(chart.currentSelection()).to.be(null);
119                 expect(chart.currentIndicator()).to.be(null);
120                 expect(indicatorChangeCalls).to.be.eql([]);
121
122                 canvas = chart.content().querySelector('canvas');
123                 rect = canvas.getBoundingClientRect();
124                 canvas.dispatchEvent(new MouseEvent('mousemove', {target: canvas, clientX: rect.right - 1, clientY: rect.top + rect.height / 2, composed: true, bubbles: true}));
125
126                 CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
127                 return waitForComponentsToRender(context);
128             }).then(() => {
129                 expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(true);
130
131                 const currentView = chart.sampledTimeSeriesData('current');
132                 lastPoint = currentView.lastPoint();
133                 expect(chart.currentSelection()).to.be(null);
134                 const indicator = chart.currentIndicator();
135                 expect(indicator.view).to.be(currentView);
136                 expect(indicator.point).to.be(lastPoint);
137                 expect(indicator.isLocked).to.be(false);
138                 expect(indicatorChangeCalls).to.be.eql([[lastPoint.id, false]]);
139
140                 canvas.parentNode.dispatchEvent(new MouseEvent('mousemove', {target: canvas, clientX: rect.right + 50, clientY: rect.bottom + 50, composed: true, bubbles: true}));
141                 canvas.dispatchEvent(new MouseEvent('mouseleave', {target: canvas, clientX: rect.right + 50, clientY: rect.bottom + 50, composed: true, bubbles: true}));
142
143                 CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
144                 return waitForComponentsToRender(context);
145             }).then(() => {
146                 expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(true);
147
148                 expect(chart.currentSelection()).to.be(null);
149                 expect(chart.currentIndicator()).to.be(null);
150                 expect(indicatorChangeCalls).to.be.eql([[lastPoint.id, false], [null, false]]);
151
152                 expect(selectionChangeCount).to.be(0);
153             });
154         });
155     });
156
157     it('should not clear the locked indicator when the mouse cursor exits the chart', () => {
158         const context = new BrowsingContext();
159         return ChartTest.importChartScripts(context).then(() => {
160             const chart = ChartTest.createInteractiveChartWithSampleCluster(context);
161
162             chart.setDomain(ChartTest.sampleCluster.startTime, ChartTest.sampleCluster.endTime);
163             chart.fetchMeasurementSets();
164             ChartTest.respondWithSampleCluster(context.symbols.MockRemoteAPI.requests[0]);
165
166             const indicatorChangeCalls = [];
167             chart.listenToAction('indicatorChange', (...args) => indicatorChangeCalls.push(args));
168
169             let selectionChangeCount = 0;
170             chart.listenToAction('selectionChange', () => selectionChangeCount++);
171
172             let canvas;
173             let rect;
174             let currentView;
175             let lastPoint;
176             return waitForComponentsToRender(context).then(() => {
177                 expect(chart.currentSelection()).to.be(null);
178                 expect(chart.currentIndicator()).to.be(null);
179                 expect(indicatorChangeCalls).to.be.eql([]);
180
181                 canvas = chart.content().querySelector('canvas');
182                 rect = canvas.getBoundingClientRect();
183                 canvas.dispatchEvent(new MouseEvent('click', {target: canvas, clientX: rect.right - 1, clientY: rect.top + rect.height / 2, composed: true, bubbles: true}));
184
185                 CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
186                 return waitForComponentsToRender(context);
187             }).then(() => {
188                 expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(true);
189
190                 currentView = chart.sampledTimeSeriesData('current');
191                 lastPoint = currentView.lastPoint();
192                 expect(chart.currentSelection()).to.be(null);
193                 const indicator = chart.currentIndicator();
194                 expect(indicator.view).to.be(currentView);
195                 expect(indicator.point).to.be(lastPoint);
196                 expect(indicator.isLocked).to.be(true);
197                 expect(indicatorChangeCalls).to.be.eql([[lastPoint.id, true]]);
198
199                 canvas.parentNode.dispatchEvent(new MouseEvent('mousemove', {target: canvas, clientX: rect.right + 50, clientY: rect.bottom + 50, composed: true, bubbles: true}));
200                 canvas.dispatchEvent(new MouseEvent('mouseleave', {target: canvas, clientX: rect.right + 50, clientY: rect.bottom + 50, composed: true, bubbles: true}));
201
202                 CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
203                 return waitForComponentsToRender(context);
204             }).then(() => {
205                 expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(false);
206
207                 expect(chart.currentSelection()).to.be(null);
208                 const indicator = chart.currentIndicator();
209                 expect(indicator.view).to.be(currentView);
210                 expect(indicator.point).to.be(lastPoint);
211                 expect(indicator.isLocked).to.be(true);
212                 expect(indicatorChangeCalls).to.be.eql([[lastPoint.id, true]]);
213
214                 expect(selectionChangeCount).to.be(0);
215             })
216         });
217     });
218
219     it('should clear the locked indicator when clicked', () => {
220         const context = new BrowsingContext();
221         return ChartTest.importChartScripts(context).then(() => {
222             const chart = ChartTest.createInteractiveChartWithSampleCluster(context);
223
224             chart.setDomain(ChartTest.sampleCluster.startTime, ChartTest.sampleCluster.endTime);
225             chart.fetchMeasurementSets();
226             ChartTest.respondWithSampleCluster(context.symbols.MockRemoteAPI.requests[0]);
227
228             const indicatorChangeCalls = [];
229             chart.listenToAction('indicatorChange', (...args) => indicatorChangeCalls.push(args));
230
231             let selectionChangeCount = 0;
232             chart.listenToAction('selectionChange', () => selectionChangeCount++);
233
234             let canvas;
235             let rect;
236             let y;
237             let currentView;
238             let lastPoint;
239             return waitForComponentsToRender(context).then(() => {
240                 expect(chart.currentSelection()).to.be(null);
241                 expect(chart.currentIndicator()).to.be(null);
242                 expect(indicatorChangeCalls).to.be.eql([]);
243
244                 canvas = chart.content().querySelector('canvas');
245                 rect = canvas.getBoundingClientRect();
246                 y = rect.top + rect.height / 2;
247                 canvas.dispatchEvent(new MouseEvent('click', {target: canvas, clientX: rect.right - 1, clientY: y, composed: true, bubbles: true}));
248
249                 CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
250                 return waitForComponentsToRender(context);
251             }).then(() => {
252                 expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(true);
253
254                 currentView = chart.sampledTimeSeriesData('current');
255                 lastPoint = currentView.lastPoint();
256                 expect(chart.currentSelection()).to.be(null);
257                 const indicator = chart.currentIndicator();
258                 expect(indicator.view).to.be(currentView);
259                 expect(indicator.point).to.be(lastPoint);
260                 expect(indicator.isLocked).to.be(true);
261                 expect(indicatorChangeCalls).to.be.eql([[lastPoint.id, true]]);
262
263                 canvas.dispatchEvent(new MouseEvent('click', {target: canvas, clientX: rect.left + 1, clientY: y, composed: true, bubbles: true}));
264
265                 CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
266                 return waitForComponentsToRender(context);
267             }).then(() => {
268                 expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(true);
269
270                 expect(chart.currentSelection()).to.be(null);
271                 const firstPoint = currentView.firstPoint();
272                 const indicator = chart.currentIndicator();
273                 expect(indicator.view).to.be(currentView);
274                 expect(indicator.point).to.be(firstPoint);
275                 expect(indicator.isLocked).to.be(false);
276                 expect(indicatorChangeCalls).to.be.eql([[lastPoint.id, true], [firstPoint.id, false]]);
277
278                 expect(selectionChangeCount).to.be(0);
279             })
280         });
281     });
282
283     it('should change the selection when the mouse cursor is dragged', () => {
284         const context = new BrowsingContext();
285         return ChartTest.importChartScripts(context).then(() => {
286             const chart = ChartTest.createInteractiveChartWithSampleCluster(context, null, {selection: {lineStyle: '#f93', lineWidth: 2, fillStyle: '#ccc'}});
287
288             chart.setDomain(ChartTest.sampleCluster.startTime, ChartTest.sampleCluster.endTime);
289             chart.fetchMeasurementSets();
290             ChartTest.respondWithSampleCluster(context.symbols.MockRemoteAPI.requests[0]);
291
292             const indicatorChangeCalls = [];
293             chart.listenToAction('indicatorChange', (...args) => indicatorChangeCalls.push(args));
294
295             const selectionChangeCalls = [];
296             chart.listenToAction('selectionChange', (...args) => selectionChangeCalls.push(args));
297
298             const zoomButton = chart.content('zoom-button');
299
300             let canvas;
301             let rect;
302             let y;
303             let currentView;
304             let firstPoint;
305             let oldRange;
306             let newRange;
307             return waitForComponentsToRender(context).then(() => {
308                 expect(chart.currentSelection()).to.be(null);
309                 expect(chart.currentIndicator()).to.be(null);
310                 expect(selectionChangeCalls).to.be.eql([]);
311
312                 canvas = chart.content().querySelector('canvas');
313                 rect = canvas.getBoundingClientRect();
314                 y = rect.top + rect.height / 2;
315                 canvas.dispatchEvent(new MouseEvent('mousemove', {target: canvas, clientX: rect.left + 5, clientY: y, composed: true, bubbles: true}));
316
317                 CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
318                 return waitForComponentsToRender(context);
319             }).then(() => {
320                 expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(true);
321
322                 currentView = chart.sampledTimeSeriesData('current');
323                 firstPoint = currentView.firstPoint();
324                 expect(chart.currentSelection()).to.be(null);
325                 let indicator = chart.currentIndicator();
326                 expect(indicator.view).to.be(currentView);
327                 expect(indicator.point).to.be(firstPoint);
328                 expect(indicator.isLocked).to.be(false);
329                 expect(indicatorChangeCalls).to.be.eql([[firstPoint.id, false]]);
330                 expect(zoomButton.offsetHeight).to.be(0);
331
332                 canvas.dispatchEvent(new MouseEvent('mousedown', {target: canvas, clientX: rect.left + 5, clientY: y, composed: true, bubbles: true}));
333
334                 CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
335                 return waitForComponentsToRender(context);
336             }).then(() => {
337                 expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(false);
338
339                 expect(chart.currentSelection()).to.be(null);
340                 let indicator = chart.currentIndicator();
341                 expect(indicator.view).to.be(currentView);
342                 expect(indicator.point).to.be(firstPoint);
343                 expect(indicator.isLocked).to.be(false);
344                 expect(selectionChangeCalls).to.be.eql([]);
345                 expect(indicatorChangeCalls).to.be.eql([[firstPoint.id, false]]);
346                 expect(zoomButton.offsetHeight).to.be(0);
347
348                 canvas.dispatchEvent(new MouseEvent('mousemove', {target: canvas, clientX: rect.left + 15, clientY: y + 5, composed: true, bubbles: true}));
349
350                 CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
351                 return waitForComponentsToRender(context);
352             }).then(() => {
353                 expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(true);
354
355                 expect(chart.currentSelection()).to.not.be(null);
356                 expect(chart.currentIndicator()).to.be(null);
357                 expect(selectionChangeCalls.length).to.be(1);
358                 oldRange = selectionChangeCalls[0][0];
359                 expect(oldRange).to.be.eql(chart.currentSelection());
360                 expect(selectionChangeCalls[0][1]).to.be(false);
361                 expect(indicatorChangeCalls).to.be.eql([[firstPoint.id, false], [null, false]]);
362                 expect(zoomButton.offsetHeight).to.be(0);
363
364                 canvas.dispatchEvent(new MouseEvent('mousemove', {target: canvas, clientX: rect.right - 5, clientY: y + 5, composed: true, bubbles: true}));
365
366                 CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
367                 return waitForComponentsToRender(context);
368             }).then(() => {
369                 expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(true);
370
371                 expect(chart.currentSelection()).to.not.be(null);
372                 expect(chart.currentIndicator()).to.be(null);
373                 expect(selectionChangeCalls.length).to.be(2);
374                 newRange = selectionChangeCalls[1][0];
375                 expect(newRange).to.be.eql(chart.currentSelection());
376                 expect(newRange[0]).to.be(oldRange[0]);
377                 expect(newRange[1]).to.be.greaterThan(oldRange[1]);
378                 expect(selectionChangeCalls[1][1]).to.be(false);
379                 expect(zoomButton.offsetHeight).to.be(0);
380
381                 canvas.dispatchEvent(new MouseEvent('mouseup', {target: canvas, clientX: rect.right - 5, clientY: y + 5, composed: true, bubbles: true}));
382                 canvas.dispatchEvent(new MouseEvent('click', {target: canvas, clientX: rect.right - 5, clientY: y + 5, composed: true, bubbles: true}));
383
384                 CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
385                 return waitForComponentsToRender(context);
386             }).then(() => {
387                 expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(true);
388
389                 expect(chart.currentSelection()).to.be.eql(newRange);
390                 expect(chart.currentIndicator()).to.be(null);
391                 expect(selectionChangeCalls.length).to.be(3);
392                 expect(selectionChangeCalls[2][0]).to.be.eql(newRange);
393                 expect(selectionChangeCalls[2][1]).to.be(true);
394                 expect(zoomButton.offsetHeight).to.be(0);
395             });
396         });
397     });
398
399     it('should dispatch the "zoom" action when the zoom button is clicked', () => {
400         const context = new BrowsingContext();
401         return ChartTest.importChartScripts(context).then(() => {
402             const chart = ChartTest.createInteractiveChartWithSampleCluster(context, null, {selection: {lineStyle: '#f93', lineWidth: 2, fillStyle: '#ccc'}, zoomButton: true});
403
404             chart.setDomain(ChartTest.sampleCluster.startTime, ChartTest.sampleCluster.endTime);
405             chart.fetchMeasurementSets();
406             ChartTest.respondWithSampleCluster(context.symbols.MockRemoteAPI.requests[0]);
407
408             const zoomCalls = [];
409             chart.listenToAction('zoom', (...args) => zoomCalls.push(args));
410             const zoomButton = chart.content('zoom-button');
411
412             let selection;
413             let canvas;
414             return waitForComponentsToRender(context).then(() => {
415                 expect(zoomButton.offsetHeight).to.be(0);
416                 canvas = chart.content().querySelector('canvas');
417                 const rect = canvas.getBoundingClientRect();
418                 const y = rect.top + rect.height / 2;
419                 canvas.dispatchEvent(new MouseEvent('mousemove', {target: canvas, clientX: rect.left + 5, clientY: y, composed: true, bubbles: true}));
420                 canvas.dispatchEvent(new MouseEvent('mousedown', {target: canvas, clientX: rect.left + 5, clientY: y, composed: true, bubbles: true}));
421                 canvas.dispatchEvent(new MouseEvent('mousemove', {target: canvas, clientX: rect.right - 10, clientY: y + 5, composed: true, bubbles: true}));
422                 canvas.dispatchEvent(new MouseEvent('mouseup', {target: canvas, clientX: rect.right - 10, clientY: y + 5, composed: true, bubbles: true}));
423
424                 CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
425                 return waitForComponentsToRender(context);
426             }).then(() => {
427                 expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(true);
428
429                 selection = chart.currentSelection();
430                 expect(selection).to.not.be(null);
431                 expect(chart.currentIndicator()).to.be(null);
432                 expect(zoomButton.offsetHeight).to.not.be(0);
433                 expect(zoomCalls).to.be.eql([]);
434                 zoomButton.click();
435             }).then(() => {
436                 expect(zoomCalls).to.be.eql([[selection]]);
437
438                 CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
439                 return waitForComponentsToRender(context);
440             }).then(() => {
441                 expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(false);
442             });
443         });
444     });
445
446     it('should clear the selection when clicked', () => {
447         const context = new BrowsingContext();
448         return ChartTest.importChartScripts(context).then(() => {
449             const chart = ChartTest.createInteractiveChartWithSampleCluster(context, null, {selection: {lineStyle: '#f93', lineWidth: 2, fillStyle: '#ccc'}});
450
451             chart.setDomain(ChartTest.sampleCluster.startTime, ChartTest.sampleCluster.endTime);
452             chart.fetchMeasurementSets();
453             ChartTest.respondWithSampleCluster(context.symbols.MockRemoteAPI.requests[0]);
454
455             let canvas;
456             let rect;
457             let y;
458             return waitForComponentsToRender(context).then(() => {
459                 canvas = chart.content().querySelector('canvas');
460                 rect = canvas.getBoundingClientRect();
461                 y = rect.top + rect.height / 2;
462                 canvas.dispatchEvent(new MouseEvent('mousemove', {target: canvas, clientX: rect.left + 5, clientY: y, composed: true, bubbles: true}));
463                 canvas.dispatchEvent(new MouseEvent('mousedown', {target: canvas, clientX: rect.left + 5, clientY: y, composed: true, bubbles: true}));
464                 canvas.dispatchEvent(new MouseEvent('mousemove', {target: canvas, clientX: rect.right - 10, clientY: y + 5, composed: true, bubbles: true}));
465                 canvas.dispatchEvent(new MouseEvent('mouseup', {target: canvas, clientX: rect.right - 10, clientY: y + 5, composed: true, bubbles: true}));
466                 canvas.dispatchEvent(new MouseEvent('click', {target: canvas, clientX: rect.right - 10, clientY: y + 5, composed: true, bubbles: true}));
467
468                 CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
469                 return waitForComponentsToRender(context);
470             }).then(() => {
471                 expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(true);
472
473                 expect(chart.currentSelection()).to.not.be(null);
474                 expect(chart.currentIndicator()).to.be(null);
475
476                 canvas.dispatchEvent(new MouseEvent('click', {target: canvas, clientX: rect.left + 1, clientY: y + 5, composed: true, bubbles: true}));
477
478                 CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
479                 return waitForComponentsToRender(context);
480             }).then(() => {
481                 expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(true);
482
483                 expect(chart.currentSelection()).to.be(null);
484                 const currentView = chart.sampledTimeSeriesData('current');
485                 const indicator = chart.currentIndicator();
486                 expect(indicator.view).to.be(currentView);
487                 expect(indicator.point).to.be(currentView.firstPoint());
488                 expect(indicator.isLocked).to.be(false);
489             });
490         });
491     });
492
493     it('should dispatch "annotationClick" action when an annotation is clicked', () => {
494         const context = new BrowsingContext();
495         return ChartTest.importChartScripts(context).then(() => {
496             const chart = ChartTest.createInteractiveChartWithSampleCluster(context, null,
497                 {annotations: { textStyle: '#000', textBackground: '#fff', minWidth: 3, barHeight: 10, barSpacing: 1}});
498
499             chart.setDomain(ChartTest.sampleCluster.startTime, ChartTest.sampleCluster.endTime);
500             chart.fetchMeasurementSets();
501             ChartTest.respondWithSampleCluster(context.symbols.MockRemoteAPI.requests[0]);
502
503             const diff = ChartTest.sampleCluster.endTime - ChartTest.sampleCluster.startTime;
504             const annotations = [{
505                 startTime: ChartTest.sampleCluster.startTime + diff / 2,
506                 endTime: ChartTest.sampleCluster.endTime - diff / 4,
507                 label: 'hello, world',
508                 fillStyle: 'rgb(0, 0, 255)',
509             }]
510             chart.setAnnotations(annotations);
511
512             const annotationClickCalls = [];
513             chart.listenToAction('annotationClick', (...args) => annotationClickCalls.push(args));
514
515             let canvas;
516             let init;
517             return waitForComponentsToRender(context).then(() => {
518                 expect(annotationClickCalls).to.be.eql([]);
519                 expect(chart.content('annotation-label').textContent).to.not.contain('hello, world');
520
521                 canvas = chart.content().querySelector('canvas');
522                 const rect = canvas.getBoundingClientRect();
523                 init = {target: canvas, clientX: rect.right - rect.width / 4, clientY: rect.bottom - 5, composed: true, bubbles: true};
524                 canvas.dispatchEvent(new MouseEvent('mousemove', init));
525
526                 CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
527                 return waitForComponentsToRender(context);
528             }).then(() => {
529                 expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(true);
530
531                 expect(chart.content('annotation-label').textContent).to.contain('hello, world');
532                 expect(annotationClickCalls).to.be.eql([]);
533                 canvas.dispatchEvent(new MouseEvent('mousedown', init));
534                 canvas.dispatchEvent(new MouseEvent('mouseup', init));
535                 canvas.dispatchEvent(new MouseEvent('click', init));
536
537                 expect(annotationClickCalls).to.be.eql([[annotations[0]]]);
538
539                 CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
540                 return waitForComponentsToRender(context);
541             }).then(() => {
542                 expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(false);
543             });
544         });
545     });
546
547     describe('render', () => {
548         it('should render the unlocked indicator when options.indicator is specified', () => {
549             const context = new BrowsingContext();
550             return ChartTest.importChartScripts(context).then(() => {
551                 const chartWithoutIndicator = ChartTest.createInteractiveChartWithSampleCluster(context);
552                 const chartWithIndicator = ChartTest.createInteractiveChartWithSampleCluster(context, null,
553                     {indicator: {lineStyle: 'rgb(51, 204, 255)', lineWidth: 2, pointRadius: 2}, interactiveChart: true});
554                 const indicatorColor = {r: 51, g: 204, b: 255};
555
556                 chartWithoutIndicator.setDomain(ChartTest.sampleCluster.startTime, ChartTest.sampleCluster.endTime);
557                 chartWithoutIndicator.fetchMeasurementSets();
558                 ChartTest.respondWithSampleCluster(context.symbols.MockRemoteAPI.requests[0]);
559
560                 chartWithIndicator.setDomain(ChartTest.sampleCluster.startTime, ChartTest.sampleCluster.endTime);
561                 chartWithIndicator.fetchMeasurementSets();
562
563                 let canvasWithoutIndicator;
564                 let canvasWithIndicator;
565                 return waitForComponentsToRender(context).then(() => {
566                     canvasWithoutIndicator = chartWithoutIndicator.content().querySelector('canvas');
567                     canvasWithIndicator = chartWithIndicator.content().querySelector('canvas');
568
569                     const rect = canvasWithIndicator.getBoundingClientRect();
570                     const x = rect.right - 1;
571                     const y = rect.top + rect.height / 2;
572                     canvasWithIndicator.dispatchEvent(new MouseEvent('mousemove', {target: canvasWithIndicator, clientX: x, clientY: y, composed: true, bubbles: true}));
573
574                     CanvasTest.fillCanvasBeforeRedrawCheck(canvasWithIndicator);
575                     return waitForComponentsToRender(context);
576                 }).then(() => {
577                     expect(CanvasTest.hasCanvasBeenRedrawn(canvasWithIndicator)).to.be(true);
578
579                     const indicator = chartWithIndicator.currentIndicator();
580                     const currentView = chartWithIndicator.sampledTimeSeriesData('current');
581                     expect(indicator.view).to.be(currentView);
582                     expect(indicator.point).to.be(currentView.lastPoint());
583                     expect(indicator.isLocked).to.be(false);
584
585                     CanvasTest.expectCanvasesMismatch(canvasWithoutIndicator, canvasWithIndicator);
586                     expect(CanvasTest.canvasContainsColor(canvasWithoutIndicator, indicatorColor)).to.be(false);
587                     expect(CanvasTest.canvasContainsColor(canvasWithIndicator, indicatorColor)).to.be(true);
588                 });
589             });
590         });
591
592         it('should render the locked indicator differently from the unlocked indicator when options.lockedIndicator is specified', () => {
593             const context = new BrowsingContext();
594             return ChartTest.importChartScripts(context).then(() => {
595                 const chartOptions = {
596                     indicator: {lineStyle: 'rgb(51, 204, 255)', lineWidth: 2, pointRadius: 3},
597                     lockedIndicator: {lineStyle: 'rgb(51, 102, 204)', fillStyle: 'rgb(250, 250, 250)', lineWidth: 2, pointRadius: 3}
598                 };
599                 const unlockedColor = {r: 51, g: 204, b: 255};
600                 const lockedColor = {r: 51, g: 102, b: 204};
601                 const lockedFillColor = {r: 250, g: 250, b: 250};
602                 const chartWithUnlockedIndicator = ChartTest.createInteractiveChartWithSampleCluster(context, null, chartOptions);
603                 const chartWithLockedIndicator = ChartTest.createInteractiveChartWithSampleCluster(context, null, chartOptions);
604
605                 chartWithUnlockedIndicator.setDomain(ChartTest.sampleCluster.startTime, ChartTest.sampleCluster.endTime);
606                 chartWithUnlockedIndicator.fetchMeasurementSets();
607                 ChartTest.respondWithSampleCluster(context.symbols.MockRemoteAPI.requests[0]);
608
609                 chartWithLockedIndicator.setDomain(ChartTest.sampleCluster.startTime, ChartTest.sampleCluster.endTime);
610                 chartWithLockedIndicator.fetchMeasurementSets();
611
612                 let canvasWithUnlockedIndicator;
613                 let canvasWithLockedIndicator;
614                 return waitForComponentsToRender(context).then(() => {
615                     canvasWithUnlockedIndicator = chartWithUnlockedIndicator.content().querySelector('canvas');
616                     canvasWithLockedIndicator = chartWithLockedIndicator.content().querySelector('canvas');
617
618                     const rect = canvasWithUnlockedIndicator.getBoundingClientRect();
619                     const x = rect.right - 1;
620                     const y = rect.top + rect.height / 2;
621                     canvasWithUnlockedIndicator.dispatchEvent(new MouseEvent('mousemove', {target: canvasWithUnlockedIndicator, clientX: x, clientY: y, composed: true, bubbles: true}));
622                     canvasWithLockedIndicator.dispatchEvent(new MouseEvent('click', {target: canvasWithLockedIndicator, clientX: x, clientY: y, composed: true, bubbles: true}));
623
624                     CanvasTest.fillCanvasBeforeRedrawCheck(canvasWithUnlockedIndicator);
625                     CanvasTest.fillCanvasBeforeRedrawCheck(canvasWithLockedIndicator);
626                     return waitForComponentsToRender(context);
627                 }).then(() => {
628                     expect(CanvasTest.hasCanvasBeenRedrawn(canvasWithUnlockedIndicator)).to.be(true);
629                     expect(CanvasTest.hasCanvasBeenRedrawn(canvasWithLockedIndicator)).to.be(true);
630
631                     let indicator = chartWithUnlockedIndicator.currentIndicator();
632                     let currentView = chartWithUnlockedIndicator.sampledTimeSeriesData('current');
633                     expect(indicator.view).to.be(currentView);
634                     expect(indicator.point).to.be(currentView.lastPoint());
635                     expect(indicator.isLocked).to.be(false);
636
637                     indicator = chartWithLockedIndicator.currentIndicator();
638                     currentView = chartWithLockedIndicator.sampledTimeSeriesData('current');
639                     expect(indicator.view).to.be(currentView);
640                     expect(indicator.point).to.be(currentView.lastPoint());
641                     expect(indicator.isLocked).to.be(true);
642
643                     CanvasTest.expectCanvasesMismatch(canvasWithUnlockedIndicator, canvasWithLockedIndicator);
644                     expect(CanvasTest.canvasContainsColor(canvasWithUnlockedIndicator, unlockedColor)).to.be(true);
645                     expect(CanvasTest.canvasContainsColor(canvasWithUnlockedIndicator, lockedFillColor)).to.be(false);
646                     expect(CanvasTest.canvasContainsColor(canvasWithLockedIndicator, lockedColor)).to.be(true);
647                     expect(CanvasTest.canvasContainsColor(canvasWithLockedIndicator, lockedFillColor)).to.be(true);
648                 });
649             });
650         });
651     });
652
653     describe('moveLockedIndicatorWithNotification', () => {
654         it('should move the locked indicator to the right when forward boolean is true', () => {
655             const context = new BrowsingContext();
656             return ChartTest.importChartScripts(context).then(() => {
657                 const chart = ChartTest.createInteractiveChartWithSampleCluster(context);
658
659                 chart.setDomain(ChartTest.sampleCluster.startTime, ChartTest.sampleCluster.endTime);
660                 chart.fetchMeasurementSets();
661                 let indicatorChangeCount = 0;
662                 chart.listenToAction('indicatorChange', () => indicatorChangeCount++);
663                 ChartTest.respondWithSampleCluster(context.symbols.MockRemoteAPI.requests[0]);
664
665                 let canvas;
666                 return waitForComponentsToRender(context).then(() => {
667                     expect(indicatorChangeCount).to.be(0);
668
669                     canvas = chart.content().querySelector('canvas');
670
671                     const rect = canvas.getBoundingClientRect();
672                     const x = rect.left + 1;
673                     const y = rect.top + rect.height / 2;
674                     canvas.dispatchEvent(new MouseEvent('click', {target: canvas, clientX: x, clientY: y, composed: true, bubbles: true}));
675
676                     CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
677                     return waitForComponentsToRender(context);
678                 }).then(() => {
679                     expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(true);
680                     expect(indicatorChangeCount).to.be(1);
681
682                     let indicator = chart.currentIndicator();
683                     let currentView = chart.sampledTimeSeriesData('current');
684                     expect(indicator.view).to.be(currentView);
685                     expect(indicator.point).to.be(currentView.firstPoint());
686                     expect(indicator.isLocked).to.be(true);
687
688                     chart.moveLockedIndicatorWithNotification(true);
689
690                     CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
691                     return waitForComponentsToRender(context);
692                 }).then(() => {
693                     expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(true);
694                     expect(indicatorChangeCount).to.be(2);
695
696                     let indicator = chart.currentIndicator();
697                     let currentView = chart.sampledTimeSeriesData('current');
698                     expect(indicator.view).to.be(currentView);
699                     expect(indicator.point).to.not.be(currentView.firstPoint());
700                     expect(indicator.point).to.be(currentView.nextPoint(currentView.firstPoint()));
701                     expect(currentView.previousPoint(indicator.point)).to.be(currentView.firstPoint());
702                     expect(indicator.isLocked).to.be(true);
703                     expect(indicatorChangeCount).to.be(2);
704                 });
705             });
706         });
707
708         it('should move the locked indicator to the left when forward boolean is false', () => {
709             const context = new BrowsingContext();
710             return ChartTest.importChartScripts(context).then(() => {
711                 const chart = ChartTest.createInteractiveChartWithSampleCluster(context);
712
713                 chart.setDomain(ChartTest.sampleCluster.startTime, ChartTest.sampleCluster.endTime);
714                 chart.fetchMeasurementSets();
715                 let indicatorChangeCount = 0;
716                 chart.listenToAction('indicatorChange', () => indicatorChangeCount++);
717                 ChartTest.respondWithSampleCluster(context.symbols.MockRemoteAPI.requests[0]);
718
719                 let canvas;
720                 return waitForComponentsToRender(context).then(() => {
721                     expect(indicatorChangeCount).to.be(0);
722
723                     canvas = chart.content().querySelector('canvas');
724
725                     const rect = canvas.getBoundingClientRect();
726                     const x = rect.right - 1;
727                     const y = rect.top + rect.height / 2;
728                     canvas.dispatchEvent(new MouseEvent('click', {target: canvas, clientX: x, clientY: y, composed: true, bubbles: true}));
729
730                     CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
731                     return waitForComponentsToRender(context);
732                 }).then(() => {
733                     expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(true);
734                     expect(indicatorChangeCount).to.be(1);
735
736                     let indicator = chart.currentIndicator();
737                     let currentView = chart.sampledTimeSeriesData('current');
738                     expect(indicator.view).to.be(currentView);
739                     expect(indicator.point).to.be(currentView.lastPoint());
740                     expect(indicator.isLocked).to.be(true);
741
742                     chart.moveLockedIndicatorWithNotification(false);
743
744                     CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
745                     return waitForComponentsToRender(context);
746                 }).then(() => {
747                     expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(true);
748                     expect(indicatorChangeCount).to.be(2);
749
750                     let indicator = chart.currentIndicator();
751                     let currentView = chart.sampledTimeSeriesData('current');
752                     expect(indicator.view).to.be(currentView);
753                     expect(indicator.point).to.not.be(currentView.firstPoint());
754                     expect(indicator.point).to.be(currentView.previousPoint(currentView.lastPoint()));
755                     expect(currentView.nextPoint(indicator.point)).to.be(currentView.lastPoint());
756                     expect(indicator.isLocked).to.be(true);
757                     expect(indicatorChangeCount).to.be(2);
758                 });
759             });
760         });
761
762         it('should not move the locked indicator when there are no points within the domain', () => {
763             const context = new BrowsingContext();
764             return ChartTest.importChartScripts(context).then(() => {
765                 const chart = ChartTest.createInteractiveChartWithSampleCluster(context);
766
767                 // The domain inclues points 2, 3
768                 chart.setDomain(posixTime('2016-01-05T20:00:00Z'), posixTime('2016-01-06T00:00:00Z'));
769                 chart.fetchMeasurementSets();
770                 let indicatorChangeCount = 0;
771                 chart.listenToAction('indicatorChange', () => indicatorChangeCount++);
772                 ChartTest.respondWithSampleCluster(context.symbols.MockRemoteAPI.requests[0]);
773
774                 let canvas;
775                 let currentView;
776                 return waitForComponentsToRender(context).then(() => {
777                     expect(indicatorChangeCount).to.be(0);
778
779                     canvas = chart.content().querySelector('canvas');
780
781                     const rect = canvas.getBoundingClientRect();
782                     const x = rect.right - 1;
783                     const y = rect.top + rect.height / 2;
784                     canvas.dispatchEvent(new MouseEvent('click', {target: canvas, clientX: x, clientY: y, composed: true, bubbles: true}));
785
786                     CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
787                     return waitForComponentsToRender(context);
788                 }).then(() => {
789                     expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(true);
790                     expect(indicatorChangeCount).to.be(1);
791
792                     currentView = chart.sampledTimeSeriesData('current');
793                     expect(currentView.length()).to.be(4); // points 0 and 4 are added to draw lines extending beyond the domain.
794                     expect([...currentView].map((point) => point.id)).to.be.eql([1000, 1002, 1003, 1004]);
795
796                     const indicator = chart.currentIndicator();
797                     expect(indicator.view).to.be(currentView);
798                     expect(indicator.point.id).to.be(1003);
799                     expect(indicator.isLocked).to.be(true);
800
801                     chart.moveLockedIndicatorWithNotification(true);
802
803                     CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
804                     return waitForComponentsToRender(context);
805                 }).then(() => {
806                     expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(false);
807
808                     expect(indicatorChangeCount).to.be(1);
809                     const indicator = chart.currentIndicator();
810                     expect(indicator.view).to.be(currentView);
811                     expect(indicator.point.id).to.be(1003);
812                     expect(indicator.isLocked).to.be(true);
813
814                     chart.moveLockedIndicatorWithNotification(false);
815
816                     CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
817                     return waitForComponentsToRender(context);
818                 }).then(() => {
819                     expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(true);
820
821                     expect(indicatorChangeCount).to.be(2);
822                     const indicator = chart.currentIndicator();
823                     expect(indicator.view).to.be(currentView);
824                     expect(indicator.point.id).to.be(1002);
825                     expect(indicator.isLocked).to.be(true);
826
827                     chart.moveLockedIndicatorWithNotification(false);
828
829                     CanvasTest.fillCanvasBeforeRedrawCheck(canvas);
830                     return waitForComponentsToRender(context);
831                 }).then(() => {
832                     expect(CanvasTest.hasCanvasBeenRedrawn(canvas)).to.be(false);
833
834                     expect(indicatorChangeCount).to.be(2);
835                     const indicator = chart.currentIndicator();
836                     expect(indicator.view).to.be(currentView);
837                     expect(indicator.point.id).to.be(1002);
838                     expect(indicator.isLocked).to.be(true);
839                 });
840             });
841         });
842
843     });
844 });